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 <libgnomecanvasmm/init.h>
31 #include <pbd/error.h>
33 #include <gtkmm2ext/gtk_ui.h>
34 #include <gtkmm2ext/tearoff.h>
35 #include <gtkmm2ext/utils.h>
37 #include <ardour/audio_track.h>
38 #include <ardour/diskstream.h>
39 #include <ardour/plugin_manager.h>
40 #include <ardour/location.h>
41 #include <ardour/audioplaylist.h>
42 #include <ardour/audioregion.h>
43 #include <ardour/session.h>
44 #include <ardour/session_route.h>
45 #include <ardour/tempo.h>
46 #include <ardour/utils.h>
48 #include "ardour_ui.h"
49 #include "canvas-ruler.h"
50 #include "canvas-simpleline.h"
51 #include "canvas-simplerect.h"
52 #include "canvas-waveview.h"
53 #include "check_mark.h"
55 #include "grouped_buttons.h"
58 #include "playlist_selector.h"
59 #include "regionview.h"
60 #include "rgb_macros.h"
61 #include "selection.h"
62 #include "streamview.h"
63 #include "time_axis_view.h"
65 #include "crossfade_view.h"
67 #include "public_editor.h"
68 #include "crossfade_edit.h"
69 #include "audio_time_axis.h"
70 #include "gui_thread.h"
75 #include "imageframe_socket_handler.h"
76 /* </CMT Additions> */
80 using namespace ARDOUR;
83 using namespace Gtkmm2ext;
84 using namespace Editing;
86 /* XXX this is a hack. it ought to be the maximum value of an jack_nframes_t */
88 const double max_canvas_coordinate = 100000000.0;
89 const double Editor::timebar_height = 15.0;
91 #include "editor_xpms"
93 static const int32_t slide_index = 0;
94 static const int32_t splice_index = 1;
96 static const gchar *edit_mode_strings[] = {
102 static const gchar *snap_type_strings[] = {
126 static const gchar *snap_mode_strings[] = {
132 static const gchar *zoom_focus_strings[] = {
141 /* Soundfile drag-n-drop */
143 Gdk::Cursor* Editor::cross_hair_cursor = 0;
144 Gdk::Cursor* Editor::selector_cursor = 0;
145 Gdk::Cursor* Editor::trimmer_cursor = 0;
146 Gdk::Cursor* Editor::grabber_cursor = 0;
147 Gdk::Cursor* Editor::zoom_cursor = 0;
148 Gdk::Cursor* Editor::time_fx_cursor = 0;
149 Gdk::Cursor* Editor::fader_cursor = 0;
150 Gdk::Cursor* Editor::speaker_cursor = 0;
151 Gdk::Cursor* Editor::null_cursor = 0;
152 Gdk::Cursor* Editor::wait_cursor = 0;
153 Gdk::Cursor* Editor::timebar_cursor = 0;
155 GdkPixmap *Editor::check_pixmap = 0;
156 GdkBitmap *Editor::check_mask = 0;
157 GdkPixmap *Editor::empty_pixmap = 0;
158 GdkBitmap *Editor::empty_mask = 0;
160 Editor::Editor (AudioEngine& eng)
163 /* time display buttons */
165 minsec_label (_("Mins:Secs")),
166 bbt_label (_("Bars:Beats")),
167 smpte_label (_("SMPTE")),
168 frame_label (_("Frames")),
169 tempo_label (_("Tempo")),
170 meter_label (_("Meter")),
171 mark_label (_("Location Markers")),
172 range_mark_label (_("Range Markers")),
173 transport_mark_label (_("Loop/Punch Ranges")),
175 edit_packer (3, 3, false),
176 edit_hscroll_left_arrow (Gtk::ARROW_LEFT, Gtk::SHADOW_OUT),
177 edit_hscroll_right_arrow (Gtk::ARROW_RIGHT, Gtk::SHADOW_OUT),
179 /* tool bar related */
181 editor_mixer_button (_("editor\nmixer")),
183 selection_start_clock (X_("SelectionStartClock"), true),
184 selection_end_clock (X_("SelectionEndClock"), true),
185 edit_cursor_clock (X_("EditCursorClock"), true),
186 zoom_range_clock (X_("ZoomRangeClock"), true, true),
188 toolbar_selection_clock_table (2,3),
190 mouse_mode_button_table (2, 3),
192 mouse_select_button (_("range")),
193 mouse_move_button (_("object")),
194 mouse_gain_button (_("gain")),
195 mouse_zoom_button (_("zoom")),
196 mouse_timefx_button (_("timefx")),
197 mouse_audition_button (_("listen")),
199 automation_mode_button (_("mode")),
200 global_automation_button (_("automation")),
202 edit_mode_label (_("Edit Mode")),
203 snap_type_label (_("Snap To")),
204 snap_mode_label(_("Snap Mode")),
205 zoom_focus_label (_("Zoom Focus")),
207 /* <CMT Additions> */
208 image_socket_listener(0),
209 /* </CMT Additions> */
213 nudge_label (_("Nudge")),
214 nudge_clock (X_("NudgeClock"), true, true)
219 /* we are a singleton */
221 PublicEditor::_instance = this;
225 check_pixmap = gdk_pixmap_colormap_create_from_xpm_d (NULL,
226 gtk_widget_get_colormap (GTK_WIDGET(edit_group_list.gobj())),
227 &check_mask, NULL, (gchar **) check_xpm);
228 empty_pixmap = gdk_pixmap_colormap_create_from_xpm_d (NULL,
229 gtk_widget_get_colormap (GTK_WIDGET(edit_group_list.gobj())),
230 &empty_mask, NULL, (gchar **) empty_xpm);
234 selection = new Selection;
235 cut_buffer = new Selection;
237 selection->TimeChanged.connect (mem_fun(*this, &Editor::time_selection_changed));
238 selection->TracksChanged.connect (mem_fun(*this, &Editor::track_selection_changed));
239 selection->RegionsChanged.connect (mem_fun(*this, &Editor::region_selection_changed));
240 selection->PointsChanged.connect (mem_fun(*this, &Editor::point_selection_changed));
242 clicked_regionview = 0;
243 clicked_trackview = 0;
244 clicked_audio_trackview = 0;
245 clicked_crossfadeview = 0;
246 clicked_control_point = 0;
247 latest_regionview = 0;
248 last_update_frame = 0;
250 last_audition_region = 0;
251 current_mixer_strip = 0;
252 current_bbt_points = 0;
254 snap_type = SnapToFrame;
255 set_snap_to (snap_type);
256 snap_mode = SnapNormal;
257 set_snap_mode (snap_mode);
258 snap_threshold = 5.0;
259 bbt_beat_subdivision = 4;
262 autoscroll_timeout_tag = -1;
263 interthread_progress_window = 0;
264 current_interthread_info = 0;
265 _show_measures = true;
266 _show_waveforms = true;
267 _show_waveforms_recording = true;
268 first_action_message = 0;
270 show_gain_after_trim = false;
271 no_zoom_repos_update = false;
272 ignore_route_list_reorder = false;
273 verbose_cursor_on = true;
274 route_removal = false;
276 show_automatic_regions_in_region_list = true;
277 have_pending_keyboard_selection = false;
278 _follow_playhead = true;
279 _xfade_visibility = true;
280 editor_ruler_menu = 0;
281 no_ruler_shown_update = false;
282 edit_group_list_menu = 0;
284 region_list_menu = 0;
286 marker_menu_item = 0;
288 transport_marker_menu = 0;
289 new_transport_marker_menu = 0;
290 editor_mixer_strip_width = Wide;
291 repos_zoom_queued = false;
292 import_audio_item = 0;
293 embed_audio_item = 0;
294 region_edit_menu_split_item = 0;
296 region_edit_menu_split_multichannel_item = 0;
297 edit_hscroll_dragging = false;
299 ignore_mouse_mode_toggle = false;
300 current_stepping_trackview = 0;
302 entered_regionview = 0;
303 clear_entered_track = false;
304 _new_regionviews_show_envelope = false;
305 current_timestretch = 0;
310 location_marker_color = color_map[cLocationMarker];
311 location_range_color = color_map[cLocationRange];
312 location_cd_marker_color = color_map[cLocationCDMarker];
313 location_loop_color = color_map[cLocationLoop];
314 location_punch_color = color_map[cLocationPunch];
316 range_marker_drag_rect = 0;
317 marker_drag_line = 0;
319 mouse_mode = MouseZoom; /* force change in next call */
320 set_mouse_mode (MouseObject, true);
322 frames_per_unit = 2048; /* too early to use set_frames_per_unit */
323 zoom_focus = ZoomFocusLeft;
324 zoom_range_clock.ValueChanged.connect (mem_fun(*this, &Editor::zoom_adjustment_changed));
326 initialize_rulers ();
327 initialize_canvas ();
329 track_canvas_scroller.add (track_canvas);
330 track_canvas_scroller.set_policy (Gtk::POLICY_NEVER, Gtk::POLICY_NEVER);
331 track_canvas_scroller.set_name ("TrackCanvasScroller");
333 track_canvas_scroller.get_vadjustment()->signal_value_changed().connect (mem_fun(*this, &Editor::tie_vertical_scrolling));
334 track_canvas_scroller.get_vadjustment()->set_step_increment (10.0);
336 track_canvas_scroller.get_hadjustment()->set_lower (0.0);
337 track_canvas_scroller.get_hadjustment()->set_upper (1200.0);
338 track_canvas_scroller.get_hadjustment()->set_step_increment (20.0);
339 track_canvas_scroller.get_hadjustment()->signal_value_changed().connect (mem_fun(*this, &Editor::canvas_horizontally_scrolled));
341 edit_vscrollbar.set_adjustment(*track_canvas_scroller.get_vadjustment());
342 edit_hscrollbar.set_adjustment(*track_canvas_scroller.get_hadjustment());
344 edit_hscrollbar.signal_button_press_event().connect (mem_fun(*this, &Editor::hscroll_slider_button_press));
345 edit_hscrollbar.signal_button_release_event().connect (mem_fun(*this, &Editor::hscroll_slider_button_release));
346 edit_hscrollbar.signal_size_allocate().connect (mem_fun(*this, &Editor::hscroll_slider_allocate));
348 time_canvas_scroller.add (time_canvas);
349 time_canvas_scroller.set_policy (Gtk::POLICY_NEVER, Gtk::POLICY_NEVER);
350 time_canvas_scroller.set_hadjustment (*track_canvas_scroller.get_hadjustment());
351 time_canvas_scroller.set_name ("TimeCanvasScroller");
353 edit_controls_vbox.set_spacing (track_spacing);
354 edit_controls_hbox.pack_start (edit_controls_vbox, true, true);
355 edit_controls_scroller.add (edit_controls_hbox);
356 edit_controls_scroller.set_name ("EditControlsBase");
357 edit_controls_scroller.set_policy (Gtk::POLICY_NEVER, Gtk::POLICY_NEVER);
359 Viewport* viewport = static_cast<Viewport*> (edit_controls_scroller.get_child());
361 viewport->set_shadow_type (Gtk::SHADOW_NONE);
362 viewport->set_name ("EditControlsBase");
363 viewport->add_events (Gdk::BUTTON_PRESS_MASK|Gdk::BUTTON_RELEASE_MASK|Gdk::ENTER_NOTIFY_MASK|Gdk::LEAVE_NOTIFY_MASK);
364 viewport->signal_button_release_event().connect (mem_fun(*this, &Editor::edit_controls_button_release));
369 XMLNode* node = ARDOUR_UI::instance()->editor_settings();
372 edit_cursor_clock.ValueChanged.connect (mem_fun(*this, &Editor::edit_cursor_clock_changed));
374 time_canvas_vbox.pack_start (*minsec_ruler, false, false);
375 time_canvas_vbox.pack_start (*smpte_ruler, false, false);
376 time_canvas_vbox.pack_start (*frames_ruler, false, false);
377 time_canvas_vbox.pack_start (*bbt_ruler, false, false);
378 time_canvas_vbox.pack_start (time_canvas_scroller, true, true);
379 time_canvas_vbox.set_size_request (-1, (int)(timebar_height * visible_timebars));
381 bbt_label.set_name ("EditorTimeButton");
382 bbt_label.set_size_request (-1, (int)timebar_height);
383 bbt_label.set_alignment (1.0, 0.5);
384 bbt_label.set_padding (5,0);
385 minsec_label.set_name ("EditorTimeButton");
386 minsec_label.set_size_request (-1, (int)timebar_height);
387 minsec_label.set_alignment (1.0, 0.5);
388 minsec_label.set_padding (5,0);
389 smpte_label.set_name ("EditorTimeButton");
390 smpte_label.set_size_request (-1, (int)timebar_height);
391 smpte_label.set_alignment (1.0, 0.5);
392 smpte_label.set_padding (5,0);
393 frame_label.set_name ("EditorTimeButton");
394 frame_label.set_size_request (-1, (int)timebar_height);
395 frame_label.set_alignment (1.0, 0.5);
396 frame_label.set_padding (5,0);
397 tempo_label.set_name ("EditorTimeButton");
398 tempo_label.set_size_request (-1, (int)timebar_height);
399 tempo_label.set_alignment (1.0, 0.5);
400 tempo_label.set_padding (5,0);
401 meter_label.set_name ("EditorTimeButton");
402 meter_label.set_size_request (-1, (int)timebar_height);
403 meter_label.set_alignment (1.0, 0.5);
404 meter_label.set_padding (5,0);
405 mark_label.set_name ("EditorTimeButton");
406 mark_label.set_size_request (-1, (int)timebar_height);
407 mark_label.set_alignment (1.0, 0.5);
408 mark_label.set_padding (5,0);
409 range_mark_label.set_name ("EditorTimeButton");
410 range_mark_label.set_size_request (-1, (int)timebar_height);
411 range_mark_label.set_alignment (1.0, 0.5);
412 range_mark_label.set_padding (5,0);
413 transport_mark_label.set_name ("EditorTimeButton");
414 transport_mark_label.set_size_request (-1, (int)timebar_height);
415 transport_mark_label.set_alignment (1.0, 0.5);
416 transport_mark_label.set_padding (5,0);
418 time_button_vbox.pack_start (minsec_label, false, false);
419 time_button_vbox.pack_start (smpte_label, false, false);
420 time_button_vbox.pack_start (frame_label, false, false);
421 time_button_vbox.pack_start (bbt_label, false, false);
422 time_button_vbox.pack_start (meter_label, false, false);
423 time_button_vbox.pack_start (tempo_label, false, false);
424 time_button_vbox.pack_start (mark_label, false, false);
426 time_button_event_box.add (time_button_vbox);
428 time_button_event_box.set_events (Gdk::BUTTON_PRESS_MASK|Gdk::BUTTON_RELEASE_MASK);
429 time_button_event_box.set_name ("TimebarLabelBase");
430 time_button_event_box.signal_button_release_event().connect (mem_fun(*this, &Editor::ruler_label_button_release));
432 /* these enable us to have a dedicated window (for cursor setting, etc.)
433 for the canvas areas.
436 track_canvas_event_box.add (track_canvas_scroller);
438 time_canvas_event_box.add (time_canvas_vbox);
439 time_canvas_event_box.set_events (Gdk::BUTTON_PRESS_MASK|Gdk::BUTTON_RELEASE_MASK|Gdk::POINTER_MOTION_MASK);
442 edit_packer.set_col_spacings (0);
443 edit_packer.set_row_spacings (0);
444 edit_packer.set_homogeneous (false);
445 edit_packer.set_name ("EditorWindow");
447 // edit_packer.attach (edit_hscroll_left_arrow_event, 0, 1, 0, 1, Gtk::FILL, 0, 0, 0);
448 // edit_packer.attach (edit_hscroll_slider, 1, 2, 0, 1, Gtk::FILL|Gtk::EXPAND, 0, 0, 0);
449 // edit_packer.attach (edit_hscroll_right_arrow_event, 2, 3, 0, 1, Gtk::FILL, 0, 0, 0);
450 edit_packer.attach (edit_hscrollbar, 1, 2, 0, 1, FILL|EXPAND, FILL, 0, 0);
452 edit_packer.attach (time_button_event_box, 0, 1, 1, 2, FILL, FILL, 0, 0);
453 edit_packer.attach (time_canvas_event_box, 1, 2, 1, 2, FILL|EXPAND, FILL, 0, 0);
455 edit_packer.attach (edit_controls_scroller, 0, 1, 2, 3, FILL, FILL|EXPAND, 0, 0);
456 edit_packer.attach (track_canvas_event_box, 1, 2, 2, 3, FILL|EXPAND, FILL|EXPAND, 0, 0);
457 edit_packer.attach (edit_vscrollbar, 2, 3, 2, 3, FILL, FILL|EXPAND, 0, 0);
459 edit_frame.set_name ("BaseFrame");
460 edit_frame.set_shadow_type (SHADOW_IN);
461 edit_frame.add (edit_packer);
463 zoom_in_button.set_name ("EditorTimeButton");
464 zoom_out_button.set_name ("EditorTimeButton");
465 ARDOUR_UI::instance()->tooltips().set_tip (zoom_in_button, _("Zoom in"));
466 ARDOUR_UI::instance()->tooltips().set_tip (zoom_out_button, _("Zoom out"));
468 // zoom_onetoone_button.set_name ("EditorTimeButton");
469 zoom_out_full_button.set_name ("EditorTimeButton");
470 // ARDOUR_UI::instance()->tooltips().set_tip (zoom_onetoone_button, _("Zoom in 1:1"));
471 ARDOUR_UI::instance()->tooltips().set_tip (zoom_out_full_button, _("Zoom to session"));
473 zoom_in_button.add (*(manage (new Image (Gdk::Pixbuf::create_from_xpm_data(zoom_in_button_xpm)))));
474 zoom_out_button.add (*(manage (new Image (Gdk::Pixbuf::create_from_xpm_data(zoom_out_button_xpm)))));
475 zoom_out_full_button.add (*(manage (new Image (Gdk::Pixbuf::create_from_xpm_data(zoom_out_full_button_xpm)))));
476 // zoom_onetoone_button.add (*(manage (new Gtk::Image (zoom_onetoone_button_xpm))));
479 zoom_in_button.signal_clicked().connect (bind (mem_fun(*this, &Editor::temporal_zoom_step), false));
480 zoom_out_button.signal_clicked().connect (bind (mem_fun(*this, &Editor::temporal_zoom_step), true));
481 zoom_out_full_button.signal_clicked().connect (mem_fun(*this, &Editor::temporal_zoom_session));
482 // zoom_onetoone_button.signal_clicked().connect (bind (mem_fun(*this, &Editor::temporal_zoom), 1.0));
484 zoom_indicator_box.pack_start (zoom_out_button, false, false);
485 zoom_indicator_box.pack_start (zoom_in_button, false, false);
486 zoom_indicator_box.pack_start (zoom_range_clock, false, false);
487 // zoom_indicator_box.pack_start (zoom_onetoone_button, false, false);
488 zoom_indicator_box.pack_start (zoom_out_full_button, false, false);
490 zoom_indicator_label.set_text (_("Zoom Span"));
491 zoom_indicator_label.set_name ("ToolBarLabel");
494 zoom_indicator_vbox.set_spacing (3);
495 zoom_indicator_vbox.set_border_width (3);
496 zoom_indicator_vbox.pack_start (zoom_indicator_label, false, false);
497 zoom_indicator_vbox.pack_start (zoom_indicator_box, false, false);
500 bottom_hbox.set_border_width (3);
501 bottom_hbox.set_spacing (3);
503 route_display_model = ListStore::create(route_display_columns);
504 route_list.set_model (route_display_model);
505 route_list.append_column (_("Tracks"), route_display_columns.text);
506 route_list.set_name ("TrackListDisplay");
507 route_list.get_selection()->set_mode (Gtk::SELECTION_MULTIPLE);
508 route_list.set_reorderable (true);
510 route_list.set_size_request (75,-1);
511 route_list.set_headers_visible (true);
512 route_list.set_headers_clickable (true);
515 // route_list.signal_rows_reordered().connect (mem_fun (*this, &Editor::queue_route_list_reordered));
518 // route_display_model->set_sort_func (0, mem_fun (*this, &Editor::route_list_compare_func));
521 //route_list.set_shadow_type (Gtk::SHADOW_IN);
523 route_list_scroller.add (route_list);
524 route_list_scroller.set_policy (Gtk::POLICY_NEVER, Gtk::POLICY_AUTOMATIC);
526 route_list.get_selection()->signal_changed().connect (mem_fun (*this, &Editor::route_display_selection_changed));
527 route_list.signal_columns_changed().connect (mem_fun(*this, &Editor::route_list_column_click));
529 edit_group_list_button_label.set_text (_("Edit Groups"));
530 edit_group_list_button_label.set_name ("EditGroupTitleButton");
531 edit_group_list_button.add (edit_group_list_button_label);
532 edit_group_list_button.set_name ("EditGroupTitleButton");
534 group_model = ListStore::create(group_columns);
535 edit_group_list.set_model (group_model);
536 edit_group_list.append_column (_("active"), group_columns.is_active);
537 edit_group_list.append_column (_("groupname"), group_columns.text);
538 edit_group_list.get_column (0)->set_data (X_("colnum"), GUINT_TO_POINTER(0));
539 edit_group_list.get_column (0)->set_data (X_("colnum"), GUINT_TO_POINTER(1));
541 /* use checkbox for the active column */
543 CellRendererToggle *active_cell = dynamic_cast<CellRendererToggle*>(edit_group_list.get_column_cell_renderer (0));
544 active_cell->set_property ("activatable", true);
545 active_cell->set_property ("radio", false);
547 edit_group_list.set_name ("MixerGroupList");
548 //edit_group_list.set_shadow_type (Gtk::SHADOW_IN);
549 route_list.set_headers_visible (false);
550 edit_group_list.set_reorderable (false);
551 edit_group_list.set_size_request (75, -1);
552 edit_group_list.columns_autosize ();
553 edit_group_list.get_selection()->set_mode (Gtk::SELECTION_MULTIPLE);
555 edit_group_list_scroller.add (edit_group_list);
556 edit_group_list_scroller.set_policy (Gtk::POLICY_AUTOMATIC, Gtk::POLICY_AUTOMATIC);
558 edit_group_list_button.signal_clicked().connect (mem_fun(*this, &Editor::edit_group_list_button_clicked));
559 edit_group_list.signal_button_press_event().connect (mem_fun(*this, &Editor::edit_group_list_button_press_event));
560 edit_group_list.get_selection()->signal_changed().connect (mem_fun(*this, &Editor::edit_group_selection_changed));
562 TreeModel::Row row = *(group_model->append());
563 row[group_columns.is_active] = false;
564 row[group_columns.text] = (_("-all-"));
565 edit_group_list.get_selection()->select (row);
566 /* GTK2FIX is set_data(0) setting the is_active to false here?
567 list<string> stupid_list;
569 stupid_list.push_back ("*");
570 stupid_list.push_back (_("-all-"));
572 edit_group_list.rows().push_back (stupid_list);
573 edit_group_list.rows().back().set_data (0);
574 edit_group_list.rows().back().select();
577 edit_group_vbox.pack_start (edit_group_list_button, false, false);
578 edit_group_vbox.pack_start (edit_group_list_scroller, true, true);
580 route_list_frame.set_name ("BaseFrame");
581 route_list_frame.set_shadow_type (Gtk::SHADOW_IN);
582 route_list_frame.add (route_list_scroller);
584 edit_group_list_frame.set_name ("BaseFrame");
585 edit_group_list_frame.set_shadow_type (Gtk::SHADOW_IN);
586 edit_group_list_frame.add (edit_group_vbox);
588 route_group_vpane.add1 (route_list_frame);
589 route_group_vpane.add2 (edit_group_list_frame);
591 list_vpacker.pack_start (route_group_vpane, true, true);
593 region_list_model = TreeStore::create (region_list_columns);
594 region_list_sort_model = TreeModelSort::create (region_list_model);
595 region_list_model->set_sort_func (0, mem_fun (*this, &Editor::region_list_sorter));
597 region_list_display.set_model (region_list_sort_model);
598 region_list_display.append_column (_("Regions"), region_list_columns.name);
599 region_list_display.set_reorderable (true);
600 region_list_display.set_size_request (100, -1);
601 region_list_display.set_data ("editor", this);
602 region_list_display.set_flags (Gtk::CAN_FOCUS);
603 region_list_display.set_name ("RegionListDisplay");
605 region_list_scroller.add (region_list_display);
606 region_list_scroller.set_policy (Gtk::POLICY_NEVER, Gtk::POLICY_AUTOMATIC);
608 list<Gtk::TargetEntry> region_list_target_table;
610 region_list_target_table.push_back (TargetEntry ("STRING"));
611 region_list_target_table.push_back (TargetEntry ("text/plain"));
612 region_list_target_table.push_back (TargetEntry ("text/uri-list"));
613 region_list_target_table.push_back (TargetEntry ("application/x-rootwin-drop"));
616 // region_list_display.drag_dest_set (region_list_target_table, DEST_DEFAULT_ALL, GdkDragAction (Gdk::ACTION_COPY|Gdk::ACTION_MOVE));
617 // region_list_display.signal_drag_data_received().connect (mem_fun(*this, &Editor::region_list_display_drag_data_received));
619 region_list_display.signal_key_press_event().connect (mem_fun(*this, &Editor::region_list_display_key_press));
620 region_list_display.signal_key_release_event().connect (mem_fun(*this, &Editor::region_list_display_key_release));
621 region_list_display.signal_button_press_event().connect (mem_fun(*this, &Editor::region_list_display_button_press));
622 region_list_display.signal_button_release_event().connect (mem_fun(*this, &Editor::region_list_display_button_release));
623 region_list_display.signal_enter_notify_event().connect (mem_fun(*this, &Editor::region_list_display_enter_notify));
624 region_list_display.signal_leave_notify_event().connect (mem_fun(*this, &Editor::region_list_display_leave_notify));
625 region_list_display.get_selection()->signal_changed().connect (mem_fun(*this, &Editor::region_list_selection_changed));
627 //region_list_display.unselect_row.connect (mem_fun(*this, &Editor::region_list_display_unselected));
628 //region_list_display.signal_columns_changed().connect (mem_fun(*this, &Editor::region_list_column_click));
630 named_selection_scroller.add (named_selection_display);
631 named_selection_scroller.set_policy (Gtk::POLICY_NEVER, Gtk::POLICY_AUTOMATIC);
633 named_selection_model = TreeStore::create (named_selection_columns);
634 named_selection_display.set_model (named_selection_model);
635 named_selection_display.set_name ("RegionListDisplay");
636 named_selection_display.set_size_request (100, -1);
637 named_selection_display.set_headers_visible (true);
638 named_selection_display.set_headers_clickable (true);
639 named_selection_display.get_selection()->set_mode (Gtk::SELECTION_SINGLE);
640 named_selection_display.signal_button_press_event().connect (mem_fun(*this, &Editor::named_selection_display_button_press));
641 named_selection_display.get_selection()->signal_changed().connect (mem_fun (*this, &Editor::named_selection_display_selection_changed));
643 region_selection_vpane.pack1 (region_list_scroller, true, true);
644 region_selection_vpane.pack2 (named_selection_scroller, true, true);
646 canvas_region_list_pane.pack1 (edit_frame, true, true);
647 canvas_region_list_pane.pack2 (region_selection_vpane, true, true);
649 track_list_canvas_pane.signal_size_allocate().connect_notify (bind (mem_fun(*this, &Editor::pane_allocation_handler),
650 static_cast<Gtk::Paned*> (&track_list_canvas_pane)));
651 canvas_region_list_pane.signal_size_allocate().connect_notify (bind (mem_fun(*this, &Editor::pane_allocation_handler),
652 static_cast<Gtk::Paned*> (&canvas_region_list_pane)));
653 route_group_vpane.signal_size_allocate().connect_notify (bind (mem_fun(*this, &Editor::pane_allocation_handler),
654 static_cast<Gtk::Paned*> (&route_group_vpane)));
655 region_selection_vpane.signal_size_allocate().connect_notify (bind (mem_fun(*this, &Editor::pane_allocation_handler),
656 static_cast<Gtk::Paned*> (®ion_selection_vpane)));
658 track_list_canvas_pane.pack1 (list_vpacker, true, true);
659 track_list_canvas_pane.pack2 (canvas_region_list_pane, true, true);
661 /* provide special pane-handle event handling for easy "hide" action */
663 /* 0: collapse to show left/upper child
664 1: collapse to show right/lower child
667 route_group_vpane.set_data ("collapse-direction", (gpointer) 0);
668 region_selection_vpane.set_data ("collapse-direction", (gpointer) 0);
669 canvas_region_list_pane.set_data ("collapse-direction", (gpointer) 0);
670 track_list_canvas_pane.set_data ("collapse-direction", (gpointer) 1);
672 route_group_vpane.signal_button_release_event().connect (bind (sigc::ptr_fun (pane_handler), static_cast<Paned*> (&route_group_vpane)));
673 region_selection_vpane.signal_button_release_event().connect (bind (sigc::ptr_fun (pane_handler), static_cast<Paned*> (®ion_selection_vpane)));
674 canvas_region_list_pane.signal_button_release_event().connect (bind (sigc::ptr_fun (pane_handler), static_cast<Paned*> (&canvas_region_list_pane)));
675 track_list_canvas_pane.signal_button_release_event().connect (bind (sigc::ptr_fun (pane_handler), static_cast<Paned*> (&track_list_canvas_pane)));
677 top_hbox.pack_start (toolbar_frame, true, true);
679 HBox *hbox = manage (new HBox);
680 hbox->pack_start (track_list_canvas_pane, true, true);
682 global_vpacker.pack_start (top_hbox, false, false);
683 global_vpacker.pack_start (*hbox, true, true);
685 global_hpacker.pack_start (global_vpacker, true, true);
687 set_name ("EditorWindow");
689 vpacker.pack_end (global_hpacker, true, true);
691 _playlist_selector = new PlaylistSelector();
692 _playlist_selector->signal_delete_event().connect (bind (sigc::ptr_fun (just_hide_it), static_cast<Window *> (_playlist_selector)));
694 AudioRegionView::AudioRegionViewGoingAway.connect (mem_fun(*this, &Editor::catch_vanishing_audio_regionview));
698 nudge_forward_button.add (*(manage (new Image (Gdk::Pixbuf::create_from_xpm_data(right_arrow_xpm)))));
699 nudge_backward_button.add (*(manage (new Image (Gdk::Pixbuf::create_from_xpm_data(left_arrow_xpm)))));
701 ARDOUR_UI::instance()->tooltips().set_tip (nudge_forward_button, _("Nudge region/selection forwards"));
702 ARDOUR_UI::instance()->tooltips().set_tip (nudge_backward_button, _("Nudge region/selection backwards"));
704 nudge_forward_button.set_name ("TransportButton");
705 nudge_backward_button.set_name ("TransportButton");
707 fade_context_menu.set_name ("ArdourContextMenu");
709 install_keybindings ();
711 set_title (_("ardour: editor"));
712 set_wmclass (_("ardour_editor"), "Ardour");
715 add_events (Gdk::KEY_PRESS_MASK|Gdk::KEY_RELEASE_MASK);
717 signal_configure_event().connect (mem_fun (*ARDOUR_UI::instance(), &ARDOUR_UI::configure_handler));
718 signal_delete_event().connect (mem_fun (*ARDOUR_UI::instance(), &ARDOUR_UI::exit_on_main_window_close));
726 /* <CMT Additions> */
727 if(image_socket_listener)
729 if(image_socket_listener->is_connected())
731 image_socket_listener->close_connection() ;
734 delete image_socket_listener ;
735 image_socket_listener = 0 ;
737 /* </CMT Additions> */
741 Editor::add_toplevel_controls (Container& cont)
743 vpacker.pack_start (cont, false, false);
748 Editor::catch_vanishing_audio_regionview (AudioRegionView *rv)
750 /* note: the selection will take care of the vanishing
751 audioregionview by itself.
754 if (clicked_regionview == rv) {
755 clicked_regionview = 0;
758 if (entered_regionview == rv) {
759 set_entered_regionview (0);
764 Editor::set_entered_regionview (AudioRegionView* rv)
766 if (rv == entered_regionview) {
770 if (entered_regionview) {
771 entered_regionview->exited ();
774 if ((entered_regionview = rv) != 0) {
775 entered_regionview->entered ();
780 Editor::set_entered_track (TimeAxisView* tav)
783 entered_track->exited ();
786 if ((entered_track = tav) != 0) {
787 entered_track->entered ();
792 Editor::left_track_canvas (GdkEventCrossing *ev)
794 set_entered_track (0);
795 set_entered_regionview (0);
801 Editor::initialize_canvas ()
803 Gnome::Canvas::init ();
805 /* adjust sensitivity for "picking" items */
807 // GNOME_CANVAS(track_canvas)->close_enough = 2;
809 track_canvas.signal_event().connect (bind (mem_fun (*this, &Editor::track_canvas_event), (ArdourCanvas::Item*) 0));
810 track_canvas.set_name ("EditorMainCanvas");
811 track_canvas.add_events (Gdk::POINTER_MOTION_HINT_MASK);
812 track_canvas.signal_leave_notify_event().connect (mem_fun(*this, &Editor::left_track_canvas));
814 /* set up drag-n-drop */
815 vector<Gtk::TargetEntry> target_table;
817 target_table.push_back (TargetEntry ("STRING"));
818 target_table.push_back (TargetEntry ("text/plain"));
819 target_table.push_back (TargetEntry ("text/uri-list"));
820 target_table.push_back (TargetEntry ("application/x-rootwin-drop"));
823 // track_canvas.drag_dest_set (target_table, DEST_DEFAULT_ALL, GdkDragAction (Gdk::ACTION_COPY|Gdk::ACTION_MOVE));
824 // track_canvas.signal_drag_data_received().connect (mem_fun(*this, &Editor::track_canvas_drag_data_received));
826 /* stuff for the verbose canvas cursor */
828 Pango::FontDescription font = get_font_for_style (N_("VerboseCanvasCursor"));
830 verbose_canvas_cursor = new Gnome::Canvas::Text (*track_canvas.root());
831 verbose_canvas_cursor->set_property ("font_desc", font);
832 verbose_canvas_cursor->set_property ("anchor", GTK_ANCHOR_NW);
833 verbose_canvas_cursor->set_property ("fill_color_rgba", color_map[cVerboseCanvasCursor]);
835 verbose_cursor_visible = false;
837 /* a group to hold time (measure) lines */
839 time_line_group = new Gnome::Canvas::Group (*track_canvas.root(), 0.0, 0.0);
840 cursor_group = new Gnome::Canvas::Group (*track_canvas.root(), 0.0, 0.0);
842 time_canvas.set_name ("EditorTimeCanvas");
843 time_canvas.add_events (Gdk::POINTER_MOTION_HINT_MASK);
845 meter_group = new Gnome::Canvas::Group (*time_canvas.root(), 0.0, 0.0);
846 tempo_group = new Gnome::Canvas::Group (*time_canvas.root(), 0.0, 0.0);
847 marker_group = new Gnome::Canvas::Group (*time_canvas.root(), 0.0, timebar_height * 2.0);
848 range_marker_group = new Gnome::Canvas::Group (*time_canvas.root(), 0.0, timebar_height * 3.0);
849 transport_marker_group = new Gnome::Canvas::Group (*time_canvas.root(), 0.0, timebar_height * 4.0);
851 tempo_bar = new Gnome::Canvas::SimpleRect (*tempo_group, 0.0, 0.0, max_canvas_coordinate, timebar_height);
852 tempo_bar->set_property ("fill_color_rgba", color_map[cTempoBar]);
853 tempo_bar->set_property ("outline_pixels", 0);
855 meter_bar = new Gnome::Canvas::SimpleRect (*meter_group, 0.0, 0.0, max_canvas_coordinate, timebar_height);
856 meter_bar->set_property ("fill_color_rgba", color_map[cMeterBar]);
857 meter_bar->set_property ("outline_pixels",0);
859 marker_bar = new Gnome::Canvas::SimpleRect (*marker_group, 0.0, 0.0, max_canvas_coordinate, timebar_height);
860 marker_bar->set_property ("fill_color_rgba", color_map[cMarkerBar]);
861 marker_bar->set_property ("outline_pixels", 0);
863 range_marker_bar = new Gnome::Canvas::SimpleRect (*range_marker_group, 0.0, 0.0, max_canvas_coordinate, timebar_height);
864 range_marker_bar->set_property ("fill_color_rgba", color_map[cRangeMarkerBar]);
865 range_marker_bar->set_property ("outline_pixels", 0);
867 transport_marker_bar = new Gnome::Canvas::SimpleRect (*transport_marker_group, 0.0, 0.0, max_canvas_coordinate, timebar_height);
868 transport_marker_bar->set_property ("fill_color_rgba", color_map[cTransportMarkerBar]);
869 transport_marker_bar->set_property ("outline_pixels", 0);
871 range_bar_drag_rect = new Gnome::Canvas::SimpleRect (*range_marker_group, 0.0, 0.0, max_canvas_coordinate, timebar_height);
872 range_bar_drag_rect->set_property ("fill_color_rgba", color_map[cRangeDragBarRectFill]);
873 range_bar_drag_rect->set_property ("outline_color_rgba", color_map[cRangeDragBarRect]);
874 range_bar_drag_rect->set_property ("outline_pixels", 0);
875 range_bar_drag_rect->hide ();
877 transport_bar_drag_rect = new Gnome::Canvas::SimpleRect (*transport_marker_group, 0.0, 0.0, max_canvas_coordinate, timebar_height);
878 transport_bar_drag_rect ->set_property ("fill_color_rgba", color_map[cTransportDragRectFill]);
879 transport_bar_drag_rect->set_property ("outline_color_rgba", color_map[cTransportDragRect]);
880 transport_bar_drag_rect->set_property ("outline_pixels", 0);
881 transport_bar_drag_rect->hide ();
883 marker_drag_line_points->push_back(Gnome::Art::Point(0.0, 0.0));
884 marker_drag_line_points->push_back(Gnome::Art::Point(0.0, 0.0));
886 marker_drag_line = new Gnome::Canvas::Line (*track_canvas.root());
887 marker_drag_line->set_property ("width_pixels", 1);
888 marker_drag_line->set_property("fill_color_rgba", color_map[cMarkerDragLine]);
889 marker_drag_line->set_property("points", marker_drag_line_points->gobj());
890 marker_drag_line->hide();
892 range_marker_drag_rect = new Gnome::Canvas::SimpleRect (*track_canvas.root(), 0.0, 0.0, 0.0, 0.0);
893 range_marker_drag_rect->set_property ("fill_color_rgba", color_map[cRangeDragRectFill]);
894 range_marker_drag_rect->set_property ("outline_color_rgba", color_map[cRangeDragRect]);
895 range_marker_drag_rect->hide ();
897 transport_loop_range_rect = new Gnome::Canvas::SimpleRect (*time_line_group, 0.0, 0.0, 0.0, 0.0);
898 transport_loop_range_rect->set_property ("fill_color_rgba", color_map[cTransportLoopRectFill]);
899 transport_loop_range_rect->set_property ("outline_color_rgba", color_map[cTransportLoopRect]);
900 transport_loop_range_rect->set_property ("outline_pixels", 1);
901 transport_loop_range_rect->hide();
903 transport_punch_range_rect = new Gnome::Canvas::SimpleRect (*time_line_group, 0.0, 0.0, 0.0, 0.0);
904 transport_punch_range_rect->set_property ("fill_color_rgba", color_map[cTransportPunchRectFill]);
905 transport_punch_range_rect->set_property ("outline_color_rgba", color_map[cTransportPunchRect]);
906 transport_punch_range_rect->set_property ("outline_pixels", 0);
907 transport_punch_range_rect->hide();
909 transport_loop_range_rect->lower_to_bottom (); // loop on the bottom
911 transport_punchin_line = new Gnome::Canvas::Line (*time_line_group);
912 transport_punchin_line->set_property ("x1", 0.0);
913 transport_punchin_line->set_property ("y1", 0.0);
914 transport_punchin_line->set_property ("x2", 0.0);
915 transport_punchin_line->set_property ("y2", 0.0);
917 transport_punchin_line->set_property ("outline_color_rgba", color_map[cPunchInLine]);
918 transport_punchin_line->set_property ("outline_pixels", 1);
919 transport_punchin_line->hide ();
921 transport_punchout_line = new Gnome::Canvas::Line (*time_line_group);
922 transport_punchout_line->set_property ("x1", 0.0);
923 transport_punchout_line->set_property ("y1", 0.0);
924 transport_punchout_line->set_property ("x2", 0.0);
925 transport_punchout_line->set_property ("y2", 0.0);
926 transport_punchout_line->set_property ("outline_color_rgba", color_map[cPunchOutLine]);
927 transport_punchout_line->set_property ("outline_pixels", 1);
928 transport_punchout_line->hide();
930 // used to show zoom mode active zooming
931 zoom_rect = new Gnome::Canvas::SimpleRect (*track_canvas.root(), 0.0, 0.0, 0.0, 0.0);
932 zoom_rect->set_property ("fill_color_rgba", color_map[cZoomRectFill]);
933 zoom_rect->set_property ("outline_color_rgba", color_map[cZoomRect]);
934 zoom_rect->set_property ("outline_pixels", 1);
937 zoom_rect->signal_event().connect (bind (mem_fun (*this, &Editor::canvas_zoom_rect_event), (ArdourCanvas::Item*) 0));
939 // used as rubberband rect
940 rubberband_rect = new Gnome::Canvas::SimpleRect (*track_canvas.root(), 0.0, 0.0, 0.0, 0.0);
941 rubberband_rect->set_property ("outline_color_rgba", color_map[cRubberBandRect]);
942 rubberband_rect->set_property ("fill_color_rgba", (guint32) color_map[cRubberBandRectFill]);
943 rubberband_rect->set_property ("outline_pixels", 1);
944 rubberband_rect->hide();
946 tempo_bar->signal_event().connect (bind (mem_fun (*this, &Editor::canvas_tempo_bar_event), tempo_bar));
947 meter_bar->signal_event().connect (bind (mem_fun (*this, &Editor::canvas_meter_bar_event), meter_bar));
948 marker_bar->signal_event().connect (bind (mem_fun (*this, &Editor::canvas_marker_bar_event), marker_bar));
949 range_marker_bar->signal_event().connect (bind (mem_fun (*this, &Editor::canvas_range_marker_bar_event), range_marker_bar));
950 transport_marker_bar->signal_event().connect (bind (mem_fun (*this, &Editor::canvas_transport_marker_bar_event), transport_marker_bar));
952 /* separator lines */
954 tempo_line_points.push_back(Gnome::Art::Point(0, timebar_height));
955 tempo_line_points.push_back(Gnome::Art::Point(max_canvas_coordinate, timebar_height));
957 tempo_line = new Gnome::Canvas::Line (*tempo_group, tempo_line_points);
958 tempo_line->set_property ("width_pixels", 0);
959 tempo_line->set_property ("fill_color", Gdk::Color ("#000000"));
961 meter_line_points.push_back(Gnome::Art::Point (0, timebar_height));
962 meter_line_points.push_back(Gnome::Art::Point(max_canvas_coordinate, timebar_height));
964 meter_line = new Gnome::Canvas::Line (*meter_group, meter_line_points);
965 meter_line->set_property ("width_pixels", 0);
966 meter_line->set_property ("fill_color", Gdk::Color ("#000000"));
968 marker_line_points.push_back(Gnome::Art::Point (0, timebar_height));
969 marker_line_points.push_back(Gnome::Art::Point(max_canvas_coordinate, timebar_height));
971 marker_line = new Gnome::Canvas::Line (*marker_group, marker_line_points);
972 marker_line->set_property ("width_pixels", 0);
973 marker_line->set_property ("fill_color", Gdk::Color ("#000000"));
975 range_marker_line = new Gnome::Canvas::Line (*range_marker_group, marker_line_points);
976 range_marker_line->set_property ("width_pixels", 0);
977 range_marker_line->set_property ("fill_color", Gdk::Color ("#000000"));
979 transport_marker_line = new Gnome::Canvas::Line (*transport_marker_group, marker_line_points);
980 transport_marker_line->set_property ("width_pixels", 0);
981 transport_marker_line->set_property ("fill_color", Gdk::Color ("#000000"));
983 ZoomChanged.connect (bind (mem_fun(*this, &Editor::update_loop_range_view), false));
984 ZoomChanged.connect (bind (mem_fun(*this, &Editor::update_punch_range_view), false));
986 double time_height = timebar_height * 5;
987 double time_width = FLT_MAX/frames_per_unit;
988 time_canvas.set_scroll_region(0.0, 0.0, time_width, time_height);
990 edit_cursor = new Cursor (*this, "blue", &Editor::canvas_edit_cursor_event);
991 playhead_cursor = new Cursor (*this, "red", &Editor::canvas_playhead_cursor_event);
993 track_canvas.signal_size_allocate().connect (mem_fun(*this, &Editor::track_canvas_allocate));
997 Editor::show_window ()
1001 /* now reset all audio_time_axis heights, because widgets might need
1007 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
1008 tv = (static_cast<TimeAxisView*>(*i));
1009 tv->reset_height ();
1014 Editor::tie_vertical_scrolling ()
1016 edit_controls_scroller.get_vadjustment()->set_value (track_canvas_scroller.get_vadjustment()->get_value());
1018 float y1 = track_canvas_scroller.get_vadjustment()->get_value();
1019 playhead_cursor->set_y_axis(y1);
1020 edit_cursor->set_y_axis(y1);
1024 Editor::set_frames_per_unit (double fpu)
1026 jack_nframes_t frames;
1028 if (fpu == frames_per_unit) {
1036 // convert fpu to frame count
1038 frames = (jack_nframes_t) (fpu * canvas_width);
1040 /* don't allow zooms that fit more than the maximum number
1041 of frames into an 800 pixel wide space.
1044 if (max_frames / fpu < 800.0) {
1048 frames_per_unit = fpu;
1050 if (frames != zoom_range_clock.current_duration()) {
1051 zoom_range_clock.set (frames);
1054 /* only update these if we not about to call reposition_x_origin,
1055 which will do the same updates.
1059 track_canvas_scroller.get_hadjustment()->set_upper (session->current_end_frame() / frames_per_unit);
1062 if (!no_zoom_repos_update) {
1063 track_canvas_scroller.get_hadjustment()->set_value (leftmost_frame/frames_per_unit);
1064 update_hscroller ();
1065 update_fixed_rulers ();
1066 tempo_map_changed (Change (0));
1069 if (mouse_mode == MouseRange && selection->time.start () != selection->time.end_frame ()) {
1070 for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
1071 (*i)->reshow_selection (selection->time);
1075 ZoomChanged (); /* EMIT_SIGNAL */
1077 if (edit_cursor) edit_cursor->set_position (edit_cursor->current_frame);
1078 if (playhead_cursor) playhead_cursor->set_position (playhead_cursor->current_frame);
1085 Editor::instant_save ()
1087 if (!constructed || !ARDOUR_UI::instance()->session_loaded) {
1092 session->add_instant_xml(get_state(), session->path());
1094 Config->add_instant_xml(get_state(), Config->get_user_ardour_path());
1099 Editor::reposition_x_origin (jack_nframes_t frame)
1101 if (frame != leftmost_frame) {
1102 leftmost_frame = frame;
1103 double pixel = frame_to_pixel (frame);
1104 if (pixel >= track_canvas_scroller.get_hadjustment()->get_upper()) {
1105 track_canvas_scroller.get_hadjustment()->set_upper (frame_to_pixel (frame + (current_page_frames())));
1107 track_canvas_scroller.get_hadjustment()->set_value (frame/frames_per_unit);
1108 XOriginChanged (); /* EMIT_SIGNAL */
1113 Editor::edit_cursor_clock_changed()
1115 if (edit_cursor->current_frame != edit_cursor_clock.current_time()) {
1116 edit_cursor->set_position (edit_cursor_clock.current_time());
1122 Editor::zoom_adjustment_changed ()
1124 if (session == 0 || no_zoom_repos_update) {
1128 double fpu = (double) zoom_range_clock.current_duration() / (double) canvas_width;
1132 zoom_range_clock.set ((jack_nframes_t) (fpu * canvas_width));
1134 else if (fpu > session->current_end_frame() / (double) canvas_width) {
1135 fpu = session->current_end_frame() / (double) canvas_width;
1136 zoom_range_clock.set ((jack_nframes_t) (fpu * canvas_width));
1139 temporal_zoom (fpu);
1143 Editor::canvas_horizontally_scrolled ()
1145 /* XXX note the potential loss of accuracy here caused by
1146 adjustments being 32bit floats with only a 24 bit mantissa,
1147 whereas jack_nframes_t is at least a 32 bit uint32_teger.
1150 leftmost_frame = (jack_nframes_t) floor (track_canvas_scroller.get_hadjustment()->get_value() * frames_per_unit);
1152 update_hscroller ();
1153 update_fixed_rulers ();
1155 if (!edit_hscroll_dragging) {
1156 tempo_map_changed (Change (0));
1158 update_tempo_based_rulers();
1163 Editor::reposition_and_zoom (jack_nframes_t frame, double nfpu)
1165 if (!repos_zoom_queued) {
1166 Glib::signal_idle().connect (bind (mem_fun(*this, &Editor::deferred_reposition_and_zoom), frame, nfpu));
1167 repos_zoom_queued = true;
1172 Editor::deferred_reposition_and_zoom (jack_nframes_t frame, double nfpu)
1174 /* if we need to force an update to the hscroller stuff,
1175 don't set no_zoom_repos_update.
1178 no_zoom_repos_update = (frame != leftmost_frame);
1180 set_frames_per_unit (nfpu);
1181 if (no_zoom_repos_update) {
1182 reposition_x_origin (frame);
1184 no_zoom_repos_update = false;
1185 repos_zoom_queued = false;
1191 Editor::on_realize ()
1193 /* Even though we're not using acceleration, we want the
1196 Glib::RefPtr<Gdk::Pixmap> empty_pixmap = Gdk::Pixmap::create(get_window(), 1, 1, 1);
1197 Glib::RefPtr<Gdk::Pixmap> empty_bitmap = Gdk::Pixmap::create(get_window(), 1, 1, 1);
1200 track_context_menu.accelerate (*this->get_toplevel());
1201 track_region_context_menu.accelerate (*this->get_toplevel());
1203 Window::on_realize ();
1205 Gdk::Color white ("#ffffff" );
1206 null_cursor = new Gdk::Cursor(empty_pixmap, empty_bitmap, white, white, 0, 0);
1214 track_canvas_scroller.get_window()->set_cursor (*current_canvas_cursor);
1215 time_canvas_scroller.get_window()->set_cursor (*timebar_cursor);
1219 Editor::track_canvas_allocate (Gtk::Allocation alloc)
1221 canvas_width = alloc.get_width();
1222 canvas_height = alloc.get_height();
1224 if (session == 0 && !ARDOUR_UI::instance()->will_create_new_session_automatically()) {
1226 Pango::FontDescription font = get_font_for_style (N_("FirstActionMessage"));
1228 const char *txt1 = _("Start a new session\n");
1229 const char *txt2 = _("via Session menu");
1231 /* this mess of code is here to find out how wide this text is and
1232 position the message in the center of the editor window. there
1233 are two lines, so we use the longer of the the lines to
1234 compute width, and multiply the height by 2.
1240 /* this is a dummy widget that exists so that we can get the
1241 style from the RC file.
1244 Label foo (_(txt2));
1245 Glib::RefPtr<Pango::Layout> layout;
1246 foo.set_name ("NoSessionMessage");
1247 foo.ensure_style ();
1249 layout = foo.create_pango_layout (_(txt2));
1250 layout->set_font_description (font);
1251 layout->get_pixel_size (pixel_width, pixel_height);
1253 if (first_action_message == 0) {
1255 char txt[strlen(txt1)+strlen(txt2)+1];
1257 /* merge both lines */
1259 strcpy (txt, _(txt1));
1260 strcat (txt, _(txt2));
1262 first_action_message = new Gnome::Canvas::Text (*track_canvas.root());
1263 first_action_message->set_property ("font_desc", font);
1264 first_action_message->set_property ("fill_color_rgba", color_map[cFirstActionMessage]);
1265 first_action_message->set_property ("x", (gdouble) (canvas_width - pixel_width) / 2.0);
1266 first_action_message->set_property ("y", (gdouble) (canvas_height/2.0) - (2.0 * (pixel_height)));
1267 first_action_message->set_property ("anchor", GTK_ANCHOR_NORTH_WEST);
1268 first_action_message->set_property ("text", ustring (txt));
1273 first_action_message->set_property ("x", (gdouble) (canvas_width - pixel_width) / 2.0),
1274 first_action_message->set_property ("y", (gdouble) (canvas_height/2.0) - (2.0 * (pixel_height)));
1278 zoom_range_clock.set ((jack_nframes_t) (canvas_width * frames_per_unit));
1279 edit_cursor->set_position (edit_cursor->current_frame);
1280 playhead_cursor->set_position (playhead_cursor->current_frame);
1281 reset_scrolling_region (&alloc);
1283 Resized (); /* EMIT_SIGNAL */
1287 Editor::reset_scrolling_region (Gtk::Allocation* alloc)
1289 guint32 last_canvas_unit;
1291 guint32 canvas_alloc_height, canvas_alloc_width;
1292 TrackViewList::iterator i;
1293 static bool first_time = true;
1295 /* We need to make sure that the canvas always has its
1296 scrolling region set to larger of:
1298 - the size allocated for it (within the container its packed in)
1299 - the size required to see the entire session
1301 If we don't ensure at least the first of these, the canvas
1302 does some wierd and in my view unnecessary stuff to center
1303 itself within the allocated area, which causes bad, bad
1306 XXX GnomeCanvas has fixed this, and has an option to
1307 control the centering behaviour.
1310 last_canvas_unit = (guint32) ceil ((float) max_frames / frames_per_unit);
1315 for (i = track_views.begin(); i != track_views.end(); ++i) {
1316 if ((*i)->control_parent) {
1317 height += (*i)->effective_height;
1318 height += track_spacing;
1323 height -= track_spacing;
1327 canvas_height = (guint32) height;
1330 canvas_alloc_height = alloc->get_height();
1331 canvas_alloc_width = alloc->get_width();
1333 canvas_alloc_height = track_canvas.get_height();
1334 canvas_alloc_width = track_canvas.get_width();
1337 canvas_height = max (canvas_height, canvas_alloc_height);
1338 track_canvas.set_scroll_region ( 0.0, 0.0, max (last_canvas_unit, canvas_alloc_width), canvas_height);
1340 if (edit_cursor) edit_cursor->set_length (canvas_alloc_height);
1341 if (playhead_cursor) playhead_cursor->set_length (canvas_alloc_height);
1343 if (marker_drag_line) {
1344 marker_drag_line_points->back().set_x(canvas_height);
1345 // cerr << "set mlA points, nc = " << marker_drag_line_points->num_points << endl;
1346 marker_drag_line->set_property("points", marker_drag_line_points);
1348 if (range_marker_drag_rect) {
1349 range_marker_drag_rect->set_property("y1", 0.0);
1350 range_marker_drag_rect->set_property("y2", (double) canvas_height);
1353 if (transport_loop_range_rect) {
1354 transport_loop_range_rect->set_property("y1", 0.0);
1355 transport_loop_range_rect->set_property("y2", (double) canvas_height);
1358 if (transport_punch_range_rect) {
1359 transport_punch_range_rect->set_property("y1", 0.0);
1360 transport_punch_range_rect->set_property("y2", (double) canvas_height);
1363 if (transport_punchin_line) {
1364 transport_punchin_line->set_property("y1", 0.0);
1365 transport_punchin_line->set_property("y2", (double) canvas_height);
1368 if (transport_punchout_line) {
1369 transport_punchout_line->set_property("y1", 0.0);
1370 transport_punchout_line->set_property("y2", (double) canvas_height);
1373 update_fixed_rulers ();
1375 if (is_visible() && first_time) {
1376 tempo_map_changed (Change (0));
1384 Editor::queue_session_control_changed (Session::ControlType t)
1386 Gtkmm2ext::UI::instance()->call_slot (bind (mem_fun(*this, &Editor::session_control_changed), t));
1390 Editor::session_control_changed (Session::ControlType t)
1392 // right now we're only tracking the loop and punch state
1395 case Session::AutoLoop:
1396 update_loop_range_view (true);
1398 case Session::PunchIn:
1399 case Session::PunchOut:
1400 update_punch_range_view (true);
1409 Editor::fake_add_edit_group (RouteGroup *group)
1411 Gtkmm2ext::UI::instance()->call_slot (bind (mem_fun(*this, &Editor::add_edit_group), group));
1415 Editor::fake_handle_new_audio_region (AudioRegion *region)
1417 Gtkmm2ext::UI::instance()->call_slot (bind (mem_fun(*this, &Editor::handle_new_audio_region), region));
1421 Editor::fake_handle_audio_region_removed (AudioRegion *region)
1423 Gtkmm2ext::UI::instance()->call_slot (bind (mem_fun(*this, &Editor::handle_audio_region_removed), region));
1427 Editor::fake_handle_new_duration ()
1429 Gtkmm2ext::UI::instance()->call_slot (mem_fun(*this, &Editor::handle_new_duration));
1433 Editor::start_scrolling ()
1435 scroll_connection = ARDOUR_UI::instance()->SuperRapidScreenUpdate.connect
1436 (mem_fun(*this, &Editor::update_current_screen));
1438 slower_update_connection = ARDOUR_UI::instance()->RapidScreenUpdate.connect
1439 (mem_fun(*this, &Editor::update_slower));
1443 Editor::stop_scrolling ()
1445 scroll_connection.disconnect ();
1446 slower_update_connection.disconnect ();
1450 Editor::map_position_change (jack_nframes_t frame)
1452 ENSURE_GUI_THREAD (bind (mem_fun(*this, &Editor::map_position_change), frame));
1454 if (session == 0 || !_follow_playhead) {
1458 center_screen (frame);
1459 playhead_cursor->set_position (frame);
1463 Editor::center_screen (jack_nframes_t frame)
1465 float page = canvas_width * frames_per_unit;
1467 /* if we're off the page, then scroll.
1470 if (frame < leftmost_frame || frame >= leftmost_frame + page) {
1471 center_screen_internal (frame,page);
1476 Editor::center_screen_internal (jack_nframes_t frame, float page)
1481 frame -= (jack_nframes_t) page;
1486 reposition_x_origin (frame);
1490 Editor::handle_new_duration ()
1492 reset_scrolling_region ();
1495 track_canvas_scroller.get_hadjustment()->set_upper (session->current_end_frame() / frames_per_unit);
1496 track_canvas_scroller.get_hadjustment()->set_value (leftmost_frame/frames_per_unit);
1499 update_hscroller ();
1503 Editor::update_title_s (string snap_name)
1505 ENSURE_GUI_THREAD(bind (mem_fun(*this, &Editor::update_title_s), snap_name));
1511 Editor::update_title ()
1513 ENSURE_GUI_THREAD (mem_fun(*this, &Editor::update_title));
1516 bool dirty = session->dirty();
1518 string wintitle = _("ardour: editor: ");
1524 wintitle += session->name();
1526 if (session->snap_name() != session->name()) {
1528 wintitle += session->snap_name();
1535 set_title (wintitle);
1540 Editor::connect_to_session (Session *t)
1544 if (first_action_message) {
1545 first_action_message->hide();
1548 flush_track_canvas();
1552 session->going_away.connect (mem_fun(*this, &Editor::session_going_away));
1554 /* These signals can all be emitted by a non-GUI thread. Therefore the
1555 handlers for them must not attempt to directly interact with the GUI,
1556 but use Gtkmm2ext::UI::instance()->call_slot();
1559 session_connections.push_back (session->TransportStateChange.connect (mem_fun(*this, &Editor::map_transport_state)));
1560 session_connections.push_back (session->PositionChanged.connect (mem_fun(*this, &Editor::map_position_change)));
1561 session_connections.push_back (session->RouteAdded.connect (mem_fun(*this, &Editor::handle_new_route_p)));
1562 session_connections.push_back (session->AudioRegionAdded.connect (mem_fun(*this, &Editor::fake_handle_new_audio_region)));
1563 session_connections.push_back (session->AudioRegionRemoved.connect (mem_fun(*this, &Editor::fake_handle_audio_region_removed)));
1564 session_connections.push_back (session->DurationChanged.connect (mem_fun(*this, &Editor::fake_handle_new_duration)));
1565 session_connections.push_back (session->edit_group_added.connect (mem_fun(*this, &Editor::fake_add_edit_group)));
1566 session_connections.push_back (session->NamedSelectionAdded.connect (mem_fun(*this, &Editor::handle_new_named_selection)));
1567 session_connections.push_back (session->NamedSelectionRemoved.connect (mem_fun(*this, &Editor::handle_new_named_selection)));
1568 session_connections.push_back (session->DirtyChanged.connect (mem_fun(*this, &Editor::update_title)));
1569 session_connections.push_back (session->StateSaved.connect (mem_fun(*this, &Editor::update_title_s)));
1570 session_connections.push_back (session->AskAboutPlaylistDeletion.connect (mem_fun(*this, &Editor::playlist_deletion_dialog)));
1571 session_connections.push_back (session->RegionHiddenChange.connect (mem_fun(*this, &Editor::region_hidden)));
1573 session_connections.push_back (session->SMPTEOffsetChanged.connect (mem_fun(*this, &Editor::update_just_smpte)));
1574 session_connections.push_back (session->SMPTETypeChanged.connect (mem_fun(*this, &Editor::update_just_smpte)));
1576 session_connections.push_back (session->tempo_map().StateChanged.connect (mem_fun(*this, &Editor::tempo_map_changed)));
1578 session->foreach_edit_group(this, &Editor::add_edit_group);
1580 editor_mixer_button.signal_toggled().connect (mem_fun(*this, &Editor::editor_mixer_button_toggled));
1581 editor_mixer_button.set_name (X_("EditorMixerButton"));
1583 edit_cursor_clock.set_session (session);
1584 selection_start_clock.set_session (session);
1585 selection_end_clock.set_session (session);
1586 zoom_range_clock.set_session (session);
1587 _playlist_selector->set_session (session);
1588 nudge_clock.set_session (session);
1590 switch (session->get_edit_mode()) {
1592 edit_mode_selector.set_active_text (edit_mode_strings[splice_index]);
1596 edit_mode_selector.set_active_text (edit_mode_strings[slide_index]);
1600 Location* loc = session->locations()->auto_loop_location();
1602 loc = new Location (0, session->current_end_frame(), _("Loop"),(Location::Flags) (Location::IsAutoLoop | Location::IsHidden));
1603 if (loc->start() == loc->end()) {
1604 loc->set_end (loc->start() + 1);
1606 session->locations()->add (loc, false);
1607 session->set_auto_loop_location (loc);
1611 loc->set_name (_("Loop"));
1614 loc = session->locations()->auto_punch_location();
1616 loc = new Location (0, session->current_end_frame(), _("Punch"), (Location::Flags) (Location::IsAutoPunch | Location::IsHidden));
1617 if (loc->start() == loc->end()) {
1618 loc->set_end (loc->start() + 1);
1620 session->locations()->add (loc, false);
1621 session->set_auto_punch_location (loc);
1625 loc->set_name (_("Punch"));
1628 update_loop_range_view (true);
1629 update_punch_range_view (true);
1631 session->ControlChanged.connect (mem_fun(*this, &Editor::queue_session_control_changed));
1634 refresh_location_display ();
1635 session->locations()->added.connect (mem_fun(*this, &Editor::add_new_location));
1636 session->locations()->removed.connect (mem_fun(*this, &Editor::location_gone));
1637 session->locations()->changed.connect (mem_fun(*this, &Editor::refresh_location_display));
1638 session->locations()->StateChanged.connect (mem_fun(*this, &Editor::refresh_location_display_s));
1639 session->locations()->end_location()->changed.connect (mem_fun(*this, &Editor::end_location_changed));
1641 reset_scrolling_region ();
1643 redisplay_regions ();
1644 redisplay_named_selections ();
1646 //route_list.freeze (); GTK2FIX
1647 route_display_model.clear ();
1648 session->foreach_route (this, &Editor::handle_new_route);
1649 // route_list.select_all ();
1651 //route_list.sort ();
1652 route_list_reordered ();
1653 //route_list.thaw ();
1655 if (embed_audio_item) {
1656 embed_audio_item->set_sensitive (true);
1658 if (import_audio_item) {
1659 import_audio_item->set_sensitive (true);
1662 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
1663 (static_cast<TimeAxisView*>(*i))->set_samples_per_unit (frames_per_unit);
1666 /* ::reposition_x_origin() doesn't work right here, since the old
1667 position may be zero already, and it does nothing in such
1673 track_canvas_scroller.get_hadjustment()->set_upper (session->current_end_frame() / frames_per_unit);
1674 track_canvas_scroller.get_hadjustment()->set_value (0);
1676 update_hscroller ();
1677 restore_ruler_visibility ();
1678 tempo_map_changed (Change (0));
1680 edit_cursor->set_position (0);
1681 playhead_cursor->set_position (0);
1685 XMLNode* node = ARDOUR_UI::instance()->editor_settings();
1688 /* don't show master bus in a new session */
1690 if (ARDOUR_UI::instance()->session_is_new ()) {
1692 TreeModel::Children rows = route_display_model->children();
1693 TreeModel::Children::iterator i;
1695 //route_list.freeze ();
1697 for (i = rows.begin(); i != rows.end(); ++i) {
1698 TimeAxisView *tv = (*i)[route_display_columns.tv];
1699 AudioTimeAxisView *atv;
1701 if ((atv = dynamic_cast<AudioTimeAxisView*>(tv)) != 0) {
1702 if (atv->route().master()) {
1703 route_list.get_selection()->unselect (i);
1704 //(*i)->unselect ();
1709 //route_list.thaw ();
1714 Editor::build_cursors ()
1716 Gdk::Color fg ("#ff0000"); /* Red. */
1717 Gdk::Color bg ("#0000ff"); /* Blue. */
1720 Glib::RefPtr <Gdk::Pixmap> source, mask;
1721 source = Gdk::Pixmap::create_from_data (source, hand_bits,
1722 hand_width, hand_height, 1, fg, bg);
1723 Gdk::Pixmap::create_from_data(mask, handmask_bits,
1724 handmask_width, handmask_height, 1, fg, bg);
1725 grabber_cursor = new Gdk::Cursor (source, mask, fg, bg, hand_x_hot, hand_y_hot);
1728 Gdk::Color mbg ("#000000" ); /* Black */
1729 Gdk::Color mfg ("#0000ff" ); /* Blue. */
1732 Glib::RefPtr <Gdk::Pixmap> source, mask;
1734 Gdk::Pixmap::create_from_data (source, mag_bits,
1735 mag_width, mag_height, 1, fg, bg);
1736 Gdk::Pixmap::create_from_data (mask, magmask_bits,
1737 mag_width, mag_height, 1, fg, bg);
1738 zoom_cursor = new Gdk::Cursor (source, mask, mfg, mbg, mag_x_hot, mag_y_hot);
1741 Gdk::Color fbg ("#ffffff" );
1742 Gdk::Color ffg ("#000000" );
1745 Glib::RefPtr <Gdk::Pixmap> source, mask;
1747 Gdk::Pixmap::create_from_data (source, fader_cursor_bits,
1748 fader_cursor_width, fader_cursor_height, 1, fg, bg);
1749 Gdk::Pixmap::create_from_data (mask, fader_cursor_mask_bits,
1750 fader_cursor_width, fader_cursor_height, 1, fg, bg);
1751 fader_cursor = new Gdk::Cursor (source, mask, ffg, fbg, fader_cursor_x_hot, fader_cursor_y_hot);
1755 Glib::RefPtr <Gdk::Pixmap> source, mask;
1756 Gdk::Pixmap::create_from_data (source,speaker_cursor_bits,
1757 speaker_cursor_width, speaker_cursor_height, 1, fg, bg);
1758 Gdk::Pixmap::create_from_data (mask, speaker_cursor_mask_bits,
1759 speaker_cursor_width, speaker_cursor_height, 1, fg, bg);
1760 speaker_cursor = new Gdk::Cursor (source, mask, ffg, fbg, speaker_cursor_x_hot, speaker_cursor_y_hot);
1763 cross_hair_cursor = new Gdk::Cursor (Gdk::CROSSHAIR);
1764 trimmer_cursor = new Gdk::Cursor (Gdk::SB_H_DOUBLE_ARROW);
1765 selector_cursor = new Gdk::Cursor (Gdk::XTERM);
1766 time_fx_cursor = new Gdk::Cursor (Gdk::SIZING);
1767 wait_cursor = new Gdk::Cursor (Gdk::WATCH);
1768 timebar_cursor = new Gdk::Cursor(Gdk::LEFT_PTR);
1772 Editor::popup_fade_context_menu (int button, int32_t time, Gnome::Canvas::Item* item, ItemType item_type)
1774 using namespace Menu_Helpers;
1775 AudioRegionView* arv = static_cast<AudioRegionView*> (gtk_object_get_data (GTK_OBJECT(item), "regionview"));
1778 fatal << _("programming error: fade in canvas item has no regionview data pointer!") << endmsg;
1782 MenuList& items (fade_context_menu.items());
1786 switch (item_type) {
1788 case FadeInHandleItem:
1789 if (arv->region.fade_in_active()) {
1790 items.push_back (MenuElem (_("Deactivate"), bind (mem_fun (*arv, &AudioRegionView::set_fade_in_active), false)));
1792 items.push_back (MenuElem (_("Activate"), bind (mem_fun (*arv, &AudioRegionView::set_fade_in_active), true)));
1795 items.push_back (SeparatorElem());
1797 items.push_back (MenuElem (_("Linear"), bind (mem_fun (arv->region, &AudioRegion::set_fade_in_shape), AudioRegion::Linear)));
1798 items.push_back (MenuElem (_("Slowest"), bind (mem_fun (arv->region, &AudioRegion::set_fade_in_shape), AudioRegion::LogB)));
1799 items.push_back (MenuElem (_("Slow"), bind (mem_fun (arv->region, &AudioRegion::set_fade_in_shape), AudioRegion::Fast)));
1800 items.push_back (MenuElem (_("Fast"), bind (mem_fun (arv->region, &AudioRegion::set_fade_in_shape), AudioRegion::LogA)));
1801 items.push_back (MenuElem (_("Fastest"), bind (mem_fun (arv->region, &AudioRegion::set_fade_in_shape), AudioRegion::Slow)));
1805 case FadeOutHandleItem:
1806 if (arv->region.fade_out_active()) {
1807 items.push_back (MenuElem (_("Deactivate"), bind (mem_fun (*arv, &AudioRegionView::set_fade_out_active), false)));
1809 items.push_back (MenuElem (_("Activate"), bind (mem_fun (*arv, &AudioRegionView::set_fade_out_active), true)));
1812 items.push_back (SeparatorElem());
1814 items.push_back (MenuElem (_("Linear"), bind (mem_fun (arv->region, &AudioRegion::set_fade_out_shape), AudioRegion::Linear)));
1815 items.push_back (MenuElem (_("Slowest"), bind (mem_fun (arv->region, &AudioRegion::set_fade_out_shape), AudioRegion::Fast)));
1816 items.push_back (MenuElem (_("Slow"), bind (mem_fun (arv->region, &AudioRegion::set_fade_out_shape), AudioRegion::LogB)));
1817 items.push_back (MenuElem (_("Fast"), bind (mem_fun (arv->region, &AudioRegion::set_fade_out_shape), AudioRegion::LogA)));
1818 items.push_back (MenuElem (_("Fastest"), bind (mem_fun (arv->region, &AudioRegion::set_fade_out_shape), AudioRegion::Slow)));
1822 fatal << _("programming error: ")
1823 << X_("non-fade canvas item passed to popup_fade_context_menu()")
1828 fade_context_menu.popup (button, time);
1832 Editor::popup_track_context_menu (int button, int32_t time, ItemType item_type, bool with_selection, jack_nframes_t frame)
1834 using namespace Menu_Helpers;
1835 Menu* (Editor::*build_menu_function)(jack_nframes_t);
1838 switch (item_type) {
1840 case AudioRegionViewName:
1841 case AudioRegionViewNameHighlight:
1842 if (with_selection) {
1843 build_menu_function = &Editor::build_track_selection_context_menu;
1845 build_menu_function = &Editor::build_track_region_context_menu;
1850 if (with_selection) {
1851 build_menu_function = &Editor::build_track_selection_context_menu;
1853 build_menu_function = &Editor::build_track_context_menu;
1857 case CrossfadeViewItem:
1858 build_menu_function = &Editor::build_track_crossfade_context_menu;
1862 if (clicked_audio_trackview->get_diskstream()) {
1863 build_menu_function = &Editor::build_track_context_menu;
1865 build_menu_function = &Editor::build_track_bus_context_menu;
1870 /* probably shouldn't happen but if it does, we don't care */
1874 menu = (this->*build_menu_function)(frame);
1875 menu->set_name ("ArdourContextMenu");
1877 /* now handle specific situations */
1879 switch (item_type) {
1881 case AudioRegionViewName:
1882 case AudioRegionViewNameHighlight:
1883 if (!with_selection) {
1884 if (region_edit_menu_split_item) {
1885 if (clicked_regionview && clicked_regionview->region.covers (edit_cursor->current_frame)) {
1886 region_edit_menu_split_item->set_sensitive (true);
1888 region_edit_menu_split_item->set_sensitive (false);
1891 if (region_edit_menu_split_multichannel_item) {
1892 if (clicked_regionview && clicked_regionview->region.n_channels() > 1) {
1893 region_edit_menu_split_multichannel_item->set_sensitive (true);
1895 region_edit_menu_split_multichannel_item->set_sensitive (false);
1904 case CrossfadeViewItem:
1911 /* probably shouldn't happen but if it does, we don't care */
1915 if (clicked_audio_trackview && clicked_audio_trackview->audio_track()) {
1917 /* Bounce to disk */
1919 using namespace Menu_Helpers;
1920 MenuList& edit_items = menu->items();
1922 edit_items.push_back (SeparatorElem());
1924 switch (clicked_audio_trackview->audio_track()->freeze_state()) {
1925 case AudioTrack::NoFreeze:
1926 edit_items.push_back (MenuElem (_("Freeze"), mem_fun(*this, &Editor::freeze_route)));
1929 case AudioTrack::Frozen:
1930 edit_items.push_back (MenuElem (_("Unfreeze"), mem_fun(*this, &Editor::unfreeze_route)));
1933 case AudioTrack::UnFrozen:
1934 edit_items.push_back (MenuElem (_("Freeze"), mem_fun(*this, &Editor::freeze_route)));
1940 menu->popup (button, time);
1944 Editor::build_track_context_menu (jack_nframes_t ignored)
1946 using namespace Menu_Helpers;
1948 MenuList& edit_items = track_context_menu.items();
1951 add_dstream_context_items (edit_items);
1952 return &track_context_menu;
1956 Editor::build_track_bus_context_menu (jack_nframes_t ignored)
1958 using namespace Menu_Helpers;
1960 MenuList& edit_items = track_context_menu.items();
1963 add_bus_context_items (edit_items);
1964 return &track_context_menu;
1968 Editor::build_track_region_context_menu (jack_nframes_t frame)
1970 using namespace Menu_Helpers;
1971 MenuList& edit_items = track_region_context_menu.items();
1974 AudioTimeAxisView* atv = dynamic_cast<AudioTimeAxisView*> (clicked_trackview);
1980 if ((ds = atv->get_diskstream()) && ((pl = ds->playlist()))) {
1981 Playlist::RegionList* regions = pl->regions_at ((jack_nframes_t) floor ( (double)frame * ds->speed()));
1982 for (Playlist::RegionList::iterator i = regions->begin(); i != regions->end(); ++i) {
1983 add_region_context_items (atv->view, (*i), edit_items);
1989 add_dstream_context_items (edit_items);
1991 return &track_region_context_menu;
1995 Editor::build_track_crossfade_context_menu (jack_nframes_t frame)
1997 using namespace Menu_Helpers;
1998 MenuList& edit_items = track_crossfade_context_menu.items();
1999 edit_items.clear ();
2001 AudioTimeAxisView* atv = dynamic_cast<AudioTimeAxisView*> (clicked_trackview);
2008 if ((ds = atv->get_diskstream()) && ((pl = ds->playlist()) != 0) && ((apl = dynamic_cast<AudioPlaylist*> (pl)) != 0)) {
2010 Playlist::RegionList* regions = pl->regions_at (frame);
2011 AudioPlaylist::Crossfades xfades;
2013 apl->crossfades_at (frame, xfades);
2015 bool many = xfades.size() > 1;
2017 for (AudioPlaylist::Crossfades::iterator i = xfades.begin(); i != xfades.end(); ++i) {
2018 add_crossfade_context_items (atv->view, (*i), edit_items, many);
2021 for (Playlist::RegionList::iterator i = regions->begin(); i != regions->end(); ++i) {
2022 add_region_context_items (atv->view, (*i), edit_items);
2029 add_dstream_context_items (edit_items);
2031 return &track_crossfade_context_menu;
2035 Editor::build_track_selection_context_menu (jack_nframes_t ignored)
2037 using namespace Menu_Helpers;
2038 MenuList& edit_items = track_selection_context_menu.items();
2039 edit_items.clear ();
2041 add_selection_context_items (edit_items);
2042 add_dstream_context_items (edit_items);
2044 return &track_selection_context_menu;
2048 Editor::add_crossfade_context_items (StreamView* view, Crossfade* xfade, Menu_Helpers::MenuList& edit_items, bool many)
2050 using namespace Menu_Helpers;
2051 Menu *xfade_menu = manage (new Menu);
2052 MenuList& items = xfade_menu->items();
2053 xfade_menu->set_name ("ArdourContextMenu");
2056 if (xfade->active()) {
2062 items.push_back (MenuElem (str, bind (mem_fun(*this, &Editor::toggle_xfade_active), xfade)));
2063 items.push_back (MenuElem (_("Edit"), bind (mem_fun(*this, &Editor::edit_xfade), xfade)));
2065 if (xfade->can_follow_overlap()) {
2067 if (xfade->following_overlap()) {
2068 str = _("Convert to short");
2070 str = _("Convert to full");
2073 items.push_back (MenuElem (str, bind (mem_fun(*this, &Editor::toggle_xfade_length), xfade)));
2077 str = xfade->out().name();
2079 str += xfade->in().name();
2081 str = _("Crossfade");
2084 edit_items.push_back (MenuElem (str, *xfade_menu));
2085 edit_items.push_back (SeparatorElem());
2089 Editor::xfade_edit_left_region ()
2091 if (clicked_crossfadeview) {
2092 clicked_crossfadeview->left_view.show_region_editor ();
2097 Editor::xfade_edit_right_region ()
2099 if (clicked_crossfadeview) {
2100 clicked_crossfadeview->right_view.show_region_editor ();
2105 Editor::add_region_context_items (StreamView* sv, Region* region, Menu_Helpers::MenuList& edit_items)
2107 using namespace Menu_Helpers;
2108 Menu *region_menu = manage (new Menu);
2109 MenuList& items = region_menu->items();
2110 region_menu->set_name ("ArdourContextMenu");
2112 AudioRegion* ar = 0;
2115 ar = dynamic_cast<AudioRegion*> (region);
2118 /* when this particular menu pops up, make the relevant region
2122 region_menu->signal_map_event().connect (bind (mem_fun(*this, &Editor::set_selected_regionview_from_map_event), sv, region));
2124 items.push_back (MenuElem (_("Popup region editor"), mem_fun(*this, &Editor::edit_region)));
2125 items.push_back (MenuElem (_("Raise to top layer"), mem_fun(*this, &Editor::raise_region_to_top)));
2126 items.push_back (MenuElem (_("Lower to bottom layer"), mem_fun (*this, &Editor::lower_region_to_bottom)));
2127 items.push_back (SeparatorElem());
2128 items.push_back (MenuElem (_("Define sync point"), mem_fun(*this, &Editor::set_region_sync_from_edit_cursor)));
2129 items.push_back (MenuElem (_("Remove sync point"), mem_fun(*this, &Editor::remove_region_sync)));
2130 items.push_back (SeparatorElem());
2132 items.push_back (MenuElem (_("Audition"), mem_fun(*this, &Editor::audition_selected_region)));
2133 items.push_back (MenuElem (_("Export"), mem_fun(*this, &Editor::export_region)));
2134 items.push_back (MenuElem (_("Bounce"), mem_fun(*this, &Editor::bounce_region_selection)));
2135 items.push_back (SeparatorElem());
2137 /* XXX hopefully this nonsense will go away with SigC++ 2.X, where the compiler
2138 might be able to figure out which overloaded member function to use in
2142 void (Editor::*type_A_pmf)(void (Region::*pmf)(bool), bool) = &Editor::region_selection_op;
2144 items.push_back (MenuElem (_("Lock"), bind (mem_fun(*this, type_A_pmf), &Region::set_locked, true)));
2145 items.push_back (MenuElem (_("Unlock"), bind (mem_fun(*this, type_A_pmf), &Region::set_locked, false)));
2146 items.push_back (SeparatorElem());
2148 if (region->muted()) {
2149 items.push_back (MenuElem (_("Unmute"), bind (mem_fun(*this, type_A_pmf), &Region::set_muted, false)));
2151 items.push_back (MenuElem (_("Mute"), bind (mem_fun(*this, type_A_pmf), &Region::set_muted, true)));
2153 items.push_back (SeparatorElem());
2155 items.push_back (MenuElem (_("Original position"), mem_fun(*this, &Editor::naturalize)));
2156 items.push_back (SeparatorElem());
2161 items.push_back (MenuElem (_("Toggle envelope visibility"), mem_fun(*this, &Editor::toggle_gain_envelope_visibility)));
2162 items.push_back (MenuElem (_("Toggle envelope active"), mem_fun(*this, &Editor::toggle_gain_envelope_active)));
2163 items.push_back (SeparatorElem());
2165 if (ar->scale_amplitude() != 1.0f) {
2166 items.push_back (MenuElem (_("DeNormalize"), mem_fun(*this, &Editor::denormalize_region)));
2168 items.push_back (MenuElem (_("Normalize"), mem_fun(*this, &Editor::normalize_region)));
2171 items.push_back (MenuElem (_("Reverse"), mem_fun(*this, &Editor::reverse_region)));
2172 items.push_back (SeparatorElem());
2176 Menu *nudge_menu = manage (new Menu());
2177 MenuList& nudge_items = nudge_menu->items();
2178 nudge_menu->set_name ("ArdourContextMenu");
2180 nudge_items.push_back (MenuElem (_("Nudge fwd"), (bind (mem_fun(*this, &Editor::nudge_forward), false))));
2181 nudge_items.push_back (MenuElem (_("Nudge bwd"), (bind (mem_fun(*this, &Editor::nudge_backward), false))));
2182 nudge_items.push_back (MenuElem (_("Nudge fwd by capture offset"), (mem_fun(*this, &Editor::nudge_forward_capture_offset))));
2183 nudge_items.push_back (MenuElem (_("Nudge bwd by capture offset"), (mem_fun(*this, &Editor::nudge_backward_capture_offset))));
2185 items.push_back (MenuElem (_("Nudge"), *nudge_menu));
2186 items.push_back (SeparatorElem());
2188 Menu *trim_menu = manage (new Menu);
2189 MenuList& trim_items = trim_menu->items();
2190 trim_menu->set_name ("ArdourContextMenu");
2192 trim_items.push_back (MenuElem (_("Start to edit cursor"), mem_fun(*this, &Editor::trim_region_from_edit_cursor)));
2193 trim_items.push_back (MenuElem (_("Edit cursor to end"), mem_fun(*this, &Editor::trim_region_to_edit_cursor)));
2195 items.push_back (MenuElem (_("Trim"), *trim_menu));
2196 items.push_back (SeparatorElem());
2198 items.push_back (MenuElem (_("Split"), (mem_fun(*this, &Editor::split_region))));
2199 region_edit_menu_split_item = &items.back();
2201 items.push_back (MenuElem (_("Make mono regions"), (mem_fun(*this, &Editor::split_multichannel_region))));
2202 region_edit_menu_split_multichannel_item = &items.back();
2204 items.push_back (MenuElem (_("Duplicate"), (bind (mem_fun(*this, &Editor::duplicate_dialog), true))));
2205 items.push_back (MenuElem (_("Fill Track"), (mem_fun(*this, &Editor::region_fill_track))));
2206 items.push_back (SeparatorElem());
2207 items.push_back (MenuElem (_("Remove"), mem_fun(*this, &Editor::remove_clicked_region)));
2208 items.push_back (SeparatorElem());
2209 items.push_back (MenuElem (_("Destroy"), mem_fun(*this, &Editor::destroy_clicked_region)));
2211 /* OK, stick the region submenu at the top of the list, and then add
2215 /* we have to hack up the region name because "_" has a special
2216 meaning for menu titles.
2219 string::size_type pos = 0;
2220 string menu_item_name = region->name();
2222 while ((pos = menu_item_name.find ("_", pos)) != string::npos) {
2223 menu_item_name.replace (pos, 1, "__");
2227 edit_items.push_back (MenuElem (menu_item_name, *region_menu));
2228 edit_items.push_back (SeparatorElem());
2232 Editor::add_selection_context_items (Menu_Helpers::MenuList& edit_items)
2234 using namespace Menu_Helpers;
2235 Menu *selection_menu = manage (new Menu);
2236 MenuList& items = selection_menu->items();
2237 selection_menu->set_name ("ArdourContextMenu");
2239 items.push_back (MenuElem (_("Play range"), mem_fun(*this, &Editor::play_selection)));
2240 items.push_back (MenuElem (_("Loop range"), mem_fun(*this, &Editor::set_route_loop_selection)));
2241 items.push_back (SeparatorElem());
2242 items.push_back (MenuElem (_("Create chunk from range"), mem_fun(*this, &Editor::name_selection)));
2243 items.push_back (SeparatorElem());
2244 items.push_back (MenuElem (_("Create Region"), mem_fun(*this, &Editor::new_region_from_selection)));
2245 items.push_back (MenuElem (_("Separate Region"), mem_fun(*this, &Editor::separate_region_from_selection)));
2246 items.push_back (MenuElem (_("Crop Region to range"), mem_fun(*this, &Editor::crop_region_to_selection)));
2247 items.push_back (MenuElem (_("Bounce range"), mem_fun(*this, &Editor::bounce_range_selection)));
2248 items.push_back (SeparatorElem());
2249 items.push_back (MenuElem (_("Duplicate"), bind (mem_fun(*this, &Editor::duplicate_dialog), false)));
2250 items.push_back (SeparatorElem());
2251 items.push_back (MenuElem (_("Export"), mem_fun(*this, &Editor::export_selection)));
2252 items.push_back (SeparatorElem());
2253 items.push_back (MenuElem (_("Fill range w/Region"), mem_fun(*this, &Editor::region_fill_selection)));
2255 edit_items.push_back (MenuElem (_("Range"), *selection_menu));
2256 edit_items.push_back (SeparatorElem());
2260 Editor::add_dstream_context_items (Menu_Helpers::MenuList& edit_items)
2262 using namespace Menu_Helpers;
2266 Menu *play_menu = manage (new Menu);
2267 MenuList& play_items = play_menu->items();
2268 play_menu->set_name ("ArdourContextMenu");
2270 play_items.push_back (MenuElem (_("Play from edit cursor")));
2271 play_items.push_back (MenuElem (_("Play from start"), mem_fun(*this, &Editor::play_from_start)));
2272 play_items.push_back (MenuElem (_("Play region"), mem_fun(*this, &Editor::play_selected_region)));
2273 play_items.push_back (SeparatorElem());
2274 play_items.push_back (MenuElem (_("Loop Region"), mem_fun(*this, &Editor::loop_selected_region)));
2276 edit_items.push_back (MenuElem (_("Play"), *play_menu));
2280 Menu *select_menu = manage (new Menu);
2281 MenuList& select_items = select_menu->items();
2282 select_menu->set_name ("ArdourContextMenu");
2284 select_items.push_back (MenuElem (_("Select All in track"), bind (mem_fun(*this, &Editor::select_all_in_track), false)));
2285 select_items.push_back (MenuElem (_("Select All"), bind (mem_fun(*this, &Editor::select_all), false)));
2286 select_items.push_back (MenuElem (_("Invert in track"), mem_fun(*this, &Editor::invert_selection_in_track)));
2287 select_items.push_back (MenuElem (_("Invert"), mem_fun(*this, &Editor::invert_selection)));
2288 select_items.push_back (SeparatorElem());
2289 select_items.push_back (MenuElem (_("Select loop range"), mem_fun(*this, &Editor::set_selection_from_loop)));
2290 select_items.push_back (MenuElem (_("Select punch range"), mem_fun(*this, &Editor::set_selection_from_punch)));
2291 select_items.push_back (SeparatorElem());
2293 edit_items.push_back (MenuElem (_("Select"), *select_menu));
2297 Menu *cutnpaste_menu = manage (new Menu);
2298 MenuList& cutnpaste_items = cutnpaste_menu->items();
2299 cutnpaste_menu->set_name ("ArdourContextMenu");
2301 cutnpaste_items.push_back (MenuElem (_("Cut"), mem_fun(*this, &Editor::cut)));
2302 cutnpaste_items.push_back (MenuElem (_("Copy"), mem_fun(*this, &Editor::copy)));
2303 cutnpaste_items.push_back (MenuElem (_("Paste at edit cursor"), bind (mem_fun(*this, &Editor::paste), 1.0f)));
2304 cutnpaste_items.push_back (MenuElem (_("Paste at mouse"), mem_fun(*this, &Editor::mouse_paste)));
2306 cutnpaste_items.push_back (SeparatorElem());
2308 cutnpaste_items.push_back (MenuElem (_("Align"), bind (mem_fun(*this, &Editor::align), ARDOUR::SyncPoint)));
2309 cutnpaste_items.push_back (MenuElem (_("Align Relative"), bind (mem_fun(*this, &Editor::align_relative), ARDOUR::SyncPoint)));
2311 cutnpaste_items.push_back (SeparatorElem());
2313 cutnpaste_items.push_back (MenuElem (_("Insert chunk"), bind (mem_fun(*this, &Editor::paste_named_selection), 1.0f)));
2315 cutnpaste_items.push_back (SeparatorElem());
2317 cutnpaste_items.push_back (MenuElem (_("New Region from range"), mem_fun(*this, &Editor::new_region_from_selection)));
2318 cutnpaste_items.push_back (MenuElem (_("Separate Range"), mem_fun(*this, &Editor::separate_region_from_selection)));
2320 edit_items.push_back (MenuElem (_("Edit"), *cutnpaste_menu));
2322 /* Adding new material */
2324 Menu *import_menu = manage (new Menu());
2325 MenuList& import_items = import_menu->items();
2326 import_menu->set_name ("ArdourContextMenu");
2328 import_items.push_back (MenuElem (_("Insert Region"), bind (mem_fun(*this, &Editor::insert_region_list_selection), 1.0f)));
2329 import_items.push_back (MenuElem (_("Insert external sndfile"), bind (mem_fun(*this, &Editor::insert_sndfile), false)));
2331 edit_items.push_back (MenuElem (_("Import"), *import_menu));
2335 Menu *nudge_menu = manage (new Menu());
2336 MenuList& nudge_items = nudge_menu->items();
2337 nudge_menu->set_name ("ArdourContextMenu");
2339 edit_items.push_back (SeparatorElem());
2340 nudge_items.push_back (MenuElem (_("Nudge entire track fwd"), (bind (mem_fun(*this, &Editor::nudge_track), false, true))));
2341 nudge_items.push_back (MenuElem (_("Nudge track after edit cursor fwd"), (bind (mem_fun(*this, &Editor::nudge_track), true, true))));
2342 nudge_items.push_back (MenuElem (_("Nudge entire track bwd"), (bind (mem_fun(*this, &Editor::nudge_track), false, false))));
2343 nudge_items.push_back (MenuElem (_("Nudge track after edit cursor bwd"), (bind (mem_fun(*this, &Editor::nudge_track), true, false))));
2345 edit_items.push_back (MenuElem (_("Nudge"), *nudge_menu));
2349 Editor::add_bus_context_items (Menu_Helpers::MenuList& edit_items)
2351 using namespace Menu_Helpers;
2355 Menu *play_menu = manage (new Menu);
2356 MenuList& play_items = play_menu->items();
2357 play_menu->set_name ("ArdourContextMenu");
2359 play_items.push_back (MenuElem (_("Play from edit cursor")));
2360 play_items.push_back (MenuElem (_("Play from start"), mem_fun(*this, &Editor::play_from_start)));
2361 edit_items.push_back (MenuElem (_("Play"), *play_menu));
2365 Menu *select_menu = manage (new Menu);
2366 MenuList& select_items = select_menu->items();
2367 select_menu->set_name ("ArdourContextMenu");
2369 select_items.push_back (MenuElem (_("Select All in track"), bind (mem_fun(*this, &Editor::select_all_in_track), false)));
2370 select_items.push_back (MenuElem (_("Select All"), bind (mem_fun(*this, &Editor::select_all), false)));
2371 select_items.push_back (MenuElem (_("Invert in track"), mem_fun(*this, &Editor::invert_selection_in_track)));
2372 select_items.push_back (MenuElem (_("Invert"), mem_fun(*this, &Editor::invert_selection)));
2373 select_items.push_back (SeparatorElem());
2374 select_items.push_back (MenuElem (_("Select loop range"), mem_fun(*this, &Editor::set_selection_from_loop)));
2375 select_items.push_back (MenuElem (_("Select punch range"), mem_fun(*this, &Editor::set_selection_from_punch)));
2376 select_items.push_back (SeparatorElem());
2378 edit_items.push_back (MenuElem (_("Select"), *select_menu));
2382 Menu *cutnpaste_menu = manage (new Menu);
2383 MenuList& cutnpaste_items = cutnpaste_menu->items();
2384 cutnpaste_menu->set_name ("ArdourContextMenu");
2386 cutnpaste_items.push_back (MenuElem (_("Cut"), mem_fun(*this, &Editor::cut)));
2387 cutnpaste_items.push_back (MenuElem (_("Copy"), mem_fun(*this, &Editor::copy)));
2388 cutnpaste_items.push_back (MenuElem (_("Paste"), bind (mem_fun(*this, &Editor::paste), 1.0f)));
2390 Menu *nudge_menu = manage (new Menu());
2391 MenuList& nudge_items = nudge_menu->items();
2392 nudge_menu->set_name ("ArdourContextMenu");
2394 edit_items.push_back (SeparatorElem());
2395 nudge_items.push_back (MenuElem (_("Nudge entire track fwd"), (bind (mem_fun(*this, &Editor::nudge_track), false, true))));
2396 nudge_items.push_back (MenuElem (_("Nudge track after edit cursor fwd"), (bind (mem_fun(*this, &Editor::nudge_track), true, true))));
2397 nudge_items.push_back (MenuElem (_("Nudge entire track bwd"), (bind (mem_fun(*this, &Editor::nudge_track), false, false))));
2398 nudge_items.push_back (MenuElem (_("Nudge track after edit cursor bwd"), (bind (mem_fun(*this, &Editor::nudge_track), true, false))));
2400 edit_items.push_back (MenuElem (_("Nudge"), *nudge_menu));
2403 /* CURSOR SETTING AND MARKS AND STUFF */
2406 Editor::set_snap_to (SnapType st)
2409 vector<string> txt = internationalize (snap_type_strings);
2410 snap_type_selector.set_active_text (txt[(int)st]);
2414 switch (snap_type) {
2415 case SnapToAThirtysecondBeat:
2416 case SnapToASixteenthBeat:
2417 case SnapToAEighthBeat:
2418 case SnapToAQuarterBeat:
2419 case SnapToAThirdBeat:
2420 update_tempo_based_rulers ();
2428 Editor::set_snap_mode (SnapMode mode)
2431 vector<string> txt = internationalize (snap_mode_strings);
2432 snap_mode_selector.set_active_text (txt[(int)mode]);
2438 Editor::add_location_from_selection ()
2440 if (selection->time.empty()) {
2444 if (session == 0 || clicked_trackview == 0) {
2448 jack_nframes_t start = selection->time[clicked_selection].start;
2449 jack_nframes_t end = selection->time[clicked_selection].end;
2451 Location *location = new Location (start, end, "selection");
2453 session->begin_reversible_command (_("add marker"));
2454 session->add_undo (session->locations()->get_memento());
2455 session->locations()->add (location, true);
2456 session->add_redo_no_execute (session->locations()->get_memento());
2457 session->commit_reversible_command ();
2461 Editor::add_location_from_playhead_cursor ()
2463 jack_nframes_t where = session->audible_frame();
2465 Location *location = new Location (where, where, "mark", Location::IsMark);
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 ();
2475 Editor::set_state (const XMLNode& node)
2477 const XMLProperty* prop;
2479 int x, y, width, height, xoff, yoff;
2481 if ((geometry = find_named_node (node, "geometry")) == 0) {
2483 width = default_width;
2484 height = default_height;
2492 width = atoi(geometry->property("x_size")->value());
2493 height = atoi(geometry->property("y_size")->value());
2494 x = atoi(geometry->property("x_pos")->value());
2495 y = atoi(geometry->property("y_pos")->value());
2496 xoff = atoi(geometry->property("x_off")->value());
2497 yoff = atoi(geometry->property("y_off")->value());
2500 set_default_size(width, height);
2502 // set_position(x, y-yoff);
2504 if ((prop = node.property ("zoom-focus"))) {
2505 set_zoom_focus ((ZoomFocus) atoi (prop->value()));
2508 if ((prop = node.property ("zoom"))) {
2509 set_frames_per_unit (atof (prop->value()));
2512 if ((prop = node.property ("snap-to"))) {
2513 set_snap_to ((SnapType) atoi (prop->value()));
2516 if ((prop = node.property ("snap-mode"))) {
2517 set_snap_mode ((SnapMode) atoi (prop->value()));
2520 if ((prop = node.property ("show-waveforms"))) {
2521 bool yn = (prop->value() == "yes");
2522 _show_waveforms = !yn;
2523 set_show_waveforms (yn);
2526 if ((prop = node.property ("show-waveforms-recording"))) {
2527 bool yn = (prop->value() == "yes");
2528 _show_waveforms_recording = !yn;
2529 set_show_waveforms_recording (yn);
2532 if ((prop = node.property ("show-measures"))) {
2533 bool yn = (prop->value() == "yes");
2534 _show_measures = !yn;
2535 set_show_measures (yn);
2538 if ((prop = node.property ("follow-playhead"))) {
2539 bool yn = (prop->value() == "yes");
2540 _follow_playhead = !yn;
2541 set_follow_playhead (yn);
2544 if ((prop = node.property ("xfades-visible"))) {
2545 bool yn = (prop->value() == "yes");
2546 _xfade_visibility = !yn;
2547 set_xfade_visibility (yn);
2550 if ((prop = node.property ("region-list-sort-type"))) {
2551 region_list_sort_type = (Editing::RegionListSortType) -1; /* force change */
2552 reset_region_list_sort_type(str2regionlistsorttype(prop->value()));
2555 if ((prop = node.property ("mouse-mode"))) {
2556 MouseMode m = str2mousemode(prop->value());
2557 mouse_mode = MouseMode ((int) m + 1); /* lie, force mode switch */
2558 set_mouse_mode (m, true);
2560 mouse_mode = MouseGain; /* lie, to force the mode switch */
2561 set_mouse_mode (MouseObject, true);
2564 if ((prop = node.property ("editor-mixer-button"))) {
2565 editor_mixer_button.set_active(prop->value() == "yes");
2572 Editor::get_state ()
2574 XMLNode* node = new XMLNode ("Editor");
2577 if (is_realized()) {
2578 Glib::RefPtr<Gdk::Window> win = get_window();
2580 int x, y, xoff, yoff, width, height;
2581 win->get_root_origin(x, y);
2582 win->get_position(xoff, yoff);
2583 win->get_size(width, height);
2585 XMLNode* geometry = new XMLNode ("geometry");
2587 snprintf(buf, sizeof(buf), "%d", width);
2588 geometry->add_property("x_size", string(buf));
2589 snprintf(buf, sizeof(buf), "%d", height);
2590 geometry->add_property("y_size", string(buf));
2591 snprintf(buf, sizeof(buf), "%d", x);
2592 geometry->add_property("x_pos", string(buf));
2593 snprintf(buf, sizeof(buf), "%d", y);
2594 geometry->add_property("y_pos", string(buf));
2595 snprintf(buf, sizeof(buf), "%d", xoff);
2596 geometry->add_property("x_off", string(buf));
2597 snprintf(buf, sizeof(buf), "%d", yoff);
2598 geometry->add_property("y_off", string(buf));
2599 snprintf(buf,sizeof(buf), "%d",gtk_paned_get_position (static_cast<Paned*>(&canvas_region_list_pane)->gobj()));
2600 geometry->add_property("canvas_region_list_pane_pos", string(buf));
2601 snprintf(buf,sizeof(buf), "%d", gtk_paned_get_position (static_cast<Paned*>(&track_list_canvas_pane)->gobj()));
2602 geometry->add_property("track_list_canvas_pane_pos", string(buf));
2603 snprintf(buf,sizeof(buf), "%d", gtk_paned_get_position (static_cast<Paned*>(®ion_selection_vpane)->gobj()));
2604 geometry->add_property("region_selection_pane_pos", string(buf));
2605 snprintf(buf,sizeof(buf), "%d", gtk_paned_get_position (static_cast<Paned*>(&route_group_vpane)->gobj()));
2606 geometry->add_property("route_group_pane_pos", string(buf));
2608 node->add_child_nocopy (*geometry);
2611 snprintf (buf, sizeof(buf), "%d", (int) zoom_focus);
2612 node->add_property ("zoom-focus", buf);
2613 snprintf (buf, sizeof(buf), "%f", frames_per_unit);
2614 node->add_property ("zoom", buf);
2615 snprintf (buf, sizeof(buf), "%d", (int) snap_type);
2616 node->add_property ("snap-to", buf);
2617 snprintf (buf, sizeof(buf), "%d", (int) snap_mode);
2618 node->add_property ("snap-mode", buf);
2620 node->add_property ("show-waveforms", _show_waveforms ? "yes" : "no");
2621 node->add_property ("show-waveforms-recording", _show_waveforms_recording ? "yes" : "no");
2622 node->add_property ("show-measures", _show_measures ? "yes" : "no");
2623 node->add_property ("follow-playhead", _follow_playhead ? "yes" : "no");
2624 node->add_property ("xfades-visible", _xfade_visibility ? "yes" : "no");
2625 node->add_property ("region-list-sort-type", enum2str(region_list_sort_type));
2626 node->add_property ("mouse-mode", enum2str(mouse_mode));
2627 node->add_property ("editor-mixer-button", editor_mixer_button.get_active() ? "yes" : "no");
2635 Editor::trackview_by_y_position (double y)
2637 TrackViewList::iterator iter;
2640 for (iter = track_views.begin(); iter != track_views.end(); ++iter) {
2648 if (tv->y_position <= y && y < ((tv->y_position + tv->height + track_spacing))) {
2657 Editor::snap_to (jack_nframes_t& start, int32_t direction, bool for_mark)
2659 Location* before = 0;
2660 Location* after = 0;
2666 const jack_nframes_t one_second = session->frame_rate();
2667 const jack_nframes_t one_minute = session->frame_rate() * 60;
2669 jack_nframes_t presnap = start;
2671 switch (snap_type) {
2677 start = (jack_nframes_t) ceil ((double) start / (one_second / 75)) * (one_second / 75);
2679 start = (jack_nframes_t) floor ((double) start / (one_second / 75)) * (one_second / 75);
2682 case SnapToSMPTEFrame:
2684 start = (jack_nframes_t) (ceil ((double) start / session->frames_per_smpte_frame()) * session->frames_per_smpte_frame());
2686 start = (jack_nframes_t) (floor ((double) start / session->frames_per_smpte_frame()) * session->frames_per_smpte_frame());
2690 case SnapToSMPTESeconds:
2691 if (session->smpte_offset_negative())
2693 start += session->smpte_offset ();
2695 start -= session->smpte_offset ();
2697 if (direction > 0) {
2698 start = (jack_nframes_t) ceil ((double) start / one_second) * one_second;
2700 start = (jack_nframes_t) floor ((double) start / one_second) * one_second;
2703 if (session->smpte_offset_negative())
2705 start -= session->smpte_offset ();
2707 start += session->smpte_offset ();
2711 case SnapToSMPTEMinutes:
2712 if (session->smpte_offset_negative())
2714 start += session->smpte_offset ();
2716 start -= session->smpte_offset ();
2719 start = (jack_nframes_t) ceil ((double) start / one_minute) * one_minute;
2721 start = (jack_nframes_t) floor ((double) start / one_minute) * one_minute;
2723 if (session->smpte_offset_negative())
2725 start -= session->smpte_offset ();
2727 start += session->smpte_offset ();
2733 start = (jack_nframes_t) ceil ((double) start / one_second) * one_second;
2735 start = (jack_nframes_t) floor ((double) start / one_second) * one_second;
2741 start = (jack_nframes_t) ceil ((double) start / one_minute) * one_minute;
2743 start = (jack_nframes_t) floor ((double) start / one_minute) * one_minute;
2748 start = session->tempo_map().round_to_bar (start, direction);
2752 start = session->tempo_map().round_to_beat (start, direction);
2755 case SnapToAThirtysecondBeat:
2756 start = session->tempo_map().round_to_beat_subdivision (start, 32);
2759 case SnapToASixteenthBeat:
2760 start = session->tempo_map().round_to_beat_subdivision (start, 16);
2763 case SnapToAEighthBeat:
2764 start = session->tempo_map().round_to_beat_subdivision (start, 8);
2767 case SnapToAQuarterBeat:
2768 start = session->tempo_map().round_to_beat_subdivision (start, 4);
2771 case SnapToAThirdBeat:
2772 start = session->tempo_map().round_to_beat_subdivision (start, 3);
2775 case SnapToEditCursor:
2776 start = edit_cursor->current_frame;
2784 before = session->locations()->first_location_before (start);
2785 after = session->locations()->first_location_after (start);
2787 if (direction < 0) {
2789 start = before->start();
2793 } else if (direction > 0) {
2795 start = after->start();
2797 start = session->current_end_frame();
2802 /* find nearest of the two */
2803 if ((start - before->start()) < (after->start() - start)) {
2804 start = before->start();
2806 start = after->start();
2809 start = before->start();
2812 start = after->start();
2819 case SnapToRegionStart:
2820 case SnapToRegionEnd:
2821 case SnapToRegionSync:
2822 case SnapToRegionBoundary:
2823 if (!region_boundary_cache.empty()) {
2824 vector<jack_nframes_t>::iterator i;
2826 if (direction > 0) {
2827 i = std::upper_bound (region_boundary_cache.begin(), region_boundary_cache.end(), start);
2829 i = std::lower_bound (region_boundary_cache.begin(), region_boundary_cache.end(), start);
2832 if (i != region_boundary_cache.end()) {
2835 start = region_boundary_cache.back();
2841 switch (snap_mode) {
2847 if (presnap > start) {
2848 if (presnap > (start + unit_to_frame(snap_threshold))) {
2852 } else if (presnap < start) {
2853 if (presnap < (start - unit_to_frame(snap_threshold))) {
2865 Editor::setup_toolbar ()
2868 vector<ToggleButton *> mouse_mode_buttons;
2870 mouse_mode_buttons.push_back (&mouse_move_button);
2871 mouse_mode_buttons.push_back (&mouse_select_button);
2872 mouse_mode_buttons.push_back (&mouse_gain_button);
2873 mouse_mode_buttons.push_back (&mouse_zoom_button);
2874 mouse_mode_buttons.push_back (&mouse_timefx_button);
2875 mouse_mode_buttons.push_back (&mouse_audition_button);
2876 mouse_mode_button_set = new GroupedButtons (mouse_mode_buttons);
2878 mouse_mode_button_table.set_homogeneous (true);
2879 mouse_mode_button_table.set_col_spacings (2);
2880 mouse_mode_button_table.set_row_spacings (2);
2881 mouse_mode_button_table.set_border_width (5);
2883 mouse_mode_button_table.attach (mouse_move_button, 0, 1, 0, 1);
2884 mouse_mode_button_table.attach (mouse_select_button, 1, 2, 0, 1);
2885 mouse_mode_button_table.attach (mouse_zoom_button, 2, 3, 0, 1);
2887 mouse_mode_button_table.attach (mouse_gain_button, 0, 1, 1, 2);
2888 mouse_mode_button_table.attach (mouse_timefx_button, 1, 2, 1, 2);
2889 mouse_mode_button_table.attach (mouse_audition_button, 2, 3, 1, 2);
2891 mouse_mode_tearoff = manage (new TearOff (mouse_mode_button_table));
2892 mouse_mode_tearoff->set_name ("MouseModeBase");
2894 mouse_mode_tearoff->Detach.connect (bind (mem_fun(*this, &Editor::detach_tearoff), static_cast<Gtk::Box*>(&toolbar_hbox),
2895 mouse_mode_tearoff->tearoff_window()));
2896 mouse_mode_tearoff->Attach.connect (bind (mem_fun(*this, &Editor::reattach_tearoff), static_cast<Gtk::Box*> (&toolbar_hbox),
2897 mouse_mode_tearoff->tearoff_window(), 1));
2899 mouse_move_button.set_name ("MouseModeButton");
2900 mouse_select_button.set_name ("MouseModeButton");
2901 mouse_gain_button.set_name ("MouseModeButton");
2902 mouse_zoom_button.set_name ("MouseModeButton");
2903 mouse_timefx_button.set_name ("MouseModeButton");
2904 mouse_audition_button.set_name ("MouseModeButton");
2906 ARDOUR_UI::instance()->tooltips().set_tip (mouse_move_button, _("select/move objects"));
2907 ARDOUR_UI::instance()->tooltips().set_tip (mouse_select_button, _("select/move ranges"));
2908 ARDOUR_UI::instance()->tooltips().set_tip (mouse_gain_button, _("draw gain automation"));
2909 ARDOUR_UI::instance()->tooltips().set_tip (mouse_zoom_button, _("select zoom range"));
2910 ARDOUR_UI::instance()->tooltips().set_tip (mouse_timefx_button, _("stretch/shrink regions"));
2911 ARDOUR_UI::instance()->tooltips().set_tip (mouse_audition_button, _("listen to specific regions"));
2913 mouse_move_button.unset_flags (Gtk::CAN_FOCUS);
2914 mouse_select_button.unset_flags (Gtk::CAN_FOCUS);
2915 mouse_gain_button.unset_flags (Gtk::CAN_FOCUS);
2916 mouse_zoom_button.unset_flags (Gtk::CAN_FOCUS);
2917 mouse_timefx_button.unset_flags (Gtk::CAN_FOCUS);
2918 mouse_audition_button.unset_flags (Gtk::CAN_FOCUS);
2920 mouse_select_button.signal_toggled().connect (bind (mem_fun(*this, &Editor::mouse_mode_toggled), Editing::MouseRange));
2921 mouse_select_button.signal_button_release_event().connect (mem_fun(*this, &Editor::mouse_select_button_release));
2923 mouse_move_button.signal_toggled().connect (bind (mem_fun(*this, &Editor::mouse_mode_toggled), Editing::MouseObject));
2924 mouse_gain_button.signal_toggled().connect (bind (mem_fun(*this, &Editor::mouse_mode_toggled), Editing::MouseGain));
2925 mouse_zoom_button.signal_toggled().connect (bind (mem_fun(*this, &Editor::mouse_mode_toggled), Editing::MouseZoom));
2926 mouse_timefx_button.signal_toggled().connect (bind (mem_fun(*this, &Editor::mouse_mode_toggled), Editing::MouseTimeFX));
2927 mouse_audition_button.signal_toggled().connect (bind (mem_fun(*this, &Editor::mouse_mode_toggled), Editing::MouseAudition));
2929 // mouse_move_button.set_active (true);
2931 /* automation control */
2933 global_automation_button.set_name ("MouseModeButton");
2934 automation_mode_button.set_name ("MouseModeButton");
2936 automation_box.set_spacing (2);
2937 automation_box.set_border_width (2);
2938 automation_box.pack_start (global_automation_button, false, false);
2939 automation_box.pack_start (automation_mode_button, false, false);
2943 edit_mode_label.set_name ("ToolBarLabel");
2945 edit_mode_selector.set_name ("EditModeSelector");
2947 edit_mode_box.set_spacing (3);
2948 edit_mode_box.set_border_width (3);
2950 /* XXX another disgusting hack because of the way combo boxes size themselves */
2952 Gtkmm2ext::set_size_request_to_display_given_text (edit_mode_selector, "EdgtMode", 2, 10);
2953 set_popdown_strings (edit_mode_selector, internationalize (edit_mode_strings));
2954 edit_mode_box.pack_start (edit_mode_label, false, false);
2955 edit_mode_box.pack_start (edit_mode_selector, false, false);
2957 edit_mode_selector.signal_changed().connect (mem_fun(*this, &Editor::edit_mode_selection_done));
2961 snap_type_label.set_name ("ToolBarLabel");
2963 snap_type_selector.set_name ("SnapTypeSelector");
2965 snap_type_box.set_spacing (3);
2966 snap_type_box.set_border_width (3);
2968 /* XXX another disgusting hack because of the way combo boxes size themselves */
2970 const guint32 FUDGE = 10; // Combo's are stupid - they steal space from the entry for the button
2971 Gtkmm2ext::set_size_request_to_display_given_text (snap_type_selector, "Region bounds", 2+FUDGE, 10);
2972 set_popdown_strings (snap_type_selector, internationalize (snap_type_strings));
2974 snap_type_box.pack_start (snap_type_label, false, false);
2975 snap_type_box.pack_start (snap_type_selector, false, false);
2977 snap_type_selector.signal_changed().connect (mem_fun(*this, &Editor::snap_type_selection_done));
2979 /* Snap mode, not snap type */
2981 snap_mode_label.set_name ("ToolBarLabel");
2983 snap_mode_selector.set_name ("SnapModeSelector");
2985 snap_mode_box.set_spacing (3);
2986 snap_mode_box.set_border_width (3);
2988 Gtkmm2ext::set_size_request_to_display_given_text (snap_mode_selector, "SngpMode", 2, 10);
2989 set_popdown_strings (snap_mode_selector, internationalize (snap_mode_strings));
2991 snap_mode_box.pack_start (snap_mode_label, false, false);
2992 snap_mode_box.pack_start (snap_mode_selector, false, false);
2994 snap_mode_selector.signal_changed().connect (mem_fun(*this, &Editor::snap_mode_selection_done));
2996 /* Zoom focus mode */
2998 zoom_focus_label.set_name ("ToolBarLabel");
3000 zoom_focus_selector.set_name ("ZoomFocusSelector");
3002 zoom_focus_box.set_spacing (3);
3003 zoom_focus_box.set_border_width (3);
3005 /* XXX another disgusting hack because of the way combo boxes size themselves */
3007 Gtkmm2ext::set_size_request_to_display_given_text (zoom_focus_selector, "Edgt Cursor", 2, 10);
3008 set_popdown_strings (zoom_focus_selector, internationalize (zoom_focus_strings));
3010 zoom_focus_box.pack_start (zoom_focus_label, false, false);
3011 zoom_focus_box.pack_start (zoom_focus_selector, false, false);
3013 zoom_focus_selector.signal_changed().connect (mem_fun(*this, &Editor::zoom_focus_selection_done));
3015 /* selection/cursor clocks */
3017 toolbar_selection_cursor_label.set_name ("ToolBarLabel");
3018 selection_start_clock_label.set_name ("ToolBarLabel");
3019 selection_end_clock_label.set_name ("ToolBarLabel");
3020 edit_cursor_clock_label.set_name ("ToolBarLabel");
3022 selection_start_clock_label.set_text (_("Start:"));
3023 selection_end_clock_label.set_text (_("End:"));
3024 edit_cursor_clock_label.set_text (_("Edit:"));
3026 toolbar_selection_clock_table.set_border_width (5);
3027 toolbar_selection_clock_table.set_col_spacings (2);
3028 toolbar_selection_clock_table.set_homogeneous (false);
3030 // toolbar_selection_clock_table.attach (selection_start_clock_label, 0, 1, 0, 1, 0, 0, 0, 0);
3031 // toolbar_selection_clock_table.attach (selection_end_clock_label, 1, 2, 0, 1, 0, 0, 0, 0);
3032 toolbar_selection_clock_table.attach (edit_cursor_clock_label, 2, 3, 0, 1, FILL, FILL, 0, 0);
3034 // toolbar_selection_clock_table.attach (selection_start_clock, 0, 1, 1, 2, 0, 0);
3035 // toolbar_selection_clock_table.attach (selection_end_clock, 1, 2, 1, 2, 0, 0);
3036 toolbar_selection_clock_table.attach (edit_cursor_clock, 2, 3, 1, 2, FILL, FILL);
3039 // toolbar_clock_vbox.set_spacing (2);
3040 // toolbar_clock_vbox.set_border_width (10);
3041 /* the editor/mixer button will be enabled at session connect */
3043 editor_mixer_button.set_active(false);
3044 editor_mixer_button.set_sensitive(false);
3046 HBox* hbox = new HBox;
3048 hbox->pack_start (editor_mixer_button, false, false);
3049 hbox->pack_start (toolbar_selection_clock_table, false, false);
3050 hbox->pack_start (zoom_indicator_vbox, false, false);
3051 hbox->pack_start (zoom_focus_box, false, false);
3052 hbox->pack_start (snap_type_box, false, false);
3053 hbox->pack_start (snap_mode_box, false, false);
3054 hbox->pack_start (edit_mode_box, false, false);
3056 VBox *vbox = manage (new VBox);
3058 vbox->set_spacing (3);
3059 vbox->set_border_width (3);
3061 HBox *nbox = manage (new HBox);
3063 nudge_forward_button.signal_clicked().connect (bind (mem_fun(*this, &Editor::nudge_forward), false));
3064 nudge_backward_button.signal_clicked().connect (bind (mem_fun(*this, &Editor::nudge_backward), false));
3066 nbox->pack_start (nudge_backward_button, false, false);
3067 nbox->pack_start (nudge_forward_button, false, false);
3068 nbox->pack_start (nudge_clock, false, false, 5);
3070 nudge_label.set_name ("ToolBarLabel");
3072 vbox->pack_start (nudge_label, false, false);
3073 vbox->pack_start (*nbox, false, false);
3075 hbox->pack_start (*vbox, false, false);
3079 tools_tearoff = new TearOff (*hbox);
3080 tools_tearoff->set_name ("MouseModeBase");
3082 tools_tearoff->Detach.connect (bind (mem_fun(*this, &Editor::detach_tearoff), static_cast<Gtk::Box*>(&toolbar_hbox),
3083 tools_tearoff->tearoff_window()));
3084 tools_tearoff->Attach.connect (bind (mem_fun(*this, &Editor::reattach_tearoff), static_cast<Gtk::Box*> (&toolbar_hbox),
3085 tools_tearoff->tearoff_window(), 0));
3088 toolbar_hbox.set_spacing (8);
3089 toolbar_hbox.set_border_width (2);
3091 toolbar_hbox.pack_start (*tools_tearoff, false, false);
3092 toolbar_hbox.pack_start (*mouse_mode_tearoff, false, false);
3094 toolbar_base.set_name ("ToolBarBase");
3095 toolbar_base.add (toolbar_hbox);
3097 toolbar_frame.set_shadow_type (Gtk::SHADOW_OUT);
3098 toolbar_frame.set_name ("BaseFrame");
3099 toolbar_frame.add (toolbar_base);
3103 Editor::_autoscroll_canvas (void *arg)
3105 return ((Editor *) arg)->autoscroll_canvas ();
3109 Editor::autoscroll_canvas ()
3111 jack_nframes_t new_frame;
3112 bool keep_calling = true;
3114 if (autoscroll_direction < 0) {
3115 if (leftmost_frame < autoscroll_distance) {
3118 new_frame = leftmost_frame - autoscroll_distance;
3121 if (leftmost_frame > max_frames - autoscroll_distance) {
3122 new_frame = max_frames;
3124 new_frame = leftmost_frame + autoscroll_distance;
3128 if (new_frame != leftmost_frame) {
3129 reposition_x_origin (new_frame);
3132 if (new_frame == 0 || new_frame == max_frames) {
3139 if (autoscroll_cnt == 1) {
3141 /* connect the timeout so that we get called repeatedly */
3143 autoscroll_timeout_tag = gtk_timeout_add (100, _autoscroll_canvas, this);
3144 keep_calling = false;
3146 } else if (autoscroll_cnt > 10 && autoscroll_cnt < 20) {
3148 /* after about a while, speed up a bit by changing the timeout interval */
3150 autoscroll_timeout_tag = gtk_timeout_add (50, _autoscroll_canvas, this);
3151 keep_calling = false;
3153 } else if (autoscroll_cnt >= 20 && autoscroll_cnt < 30) {
3155 /* after about another while, speed up some more */
3157 autoscroll_timeout_tag = gtk_timeout_add (25, _autoscroll_canvas, this);
3158 keep_calling = false;
3160 } else if (autoscroll_cnt >= 30) {
3162 /* we've been scrolling for a while ... crank it up */
3164 autoscroll_distance = 10 * (jack_nframes_t) floor (canvas_width * frames_per_unit);
3167 return keep_calling;
3171 Editor::start_canvas_autoscroll (int dir)
3177 stop_canvas_autoscroll ();
3179 autoscroll_direction = dir;
3180 autoscroll_distance = (jack_nframes_t) floor ((canvas_width * frames_per_unit)/10.0);
3183 /* do it right now, which will start the repeated callbacks */
3185 autoscroll_canvas ();
3189 Editor::stop_canvas_autoscroll ()
3191 if (autoscroll_timeout_tag >= 0) {
3192 gtk_timeout_remove (autoscroll_timeout_tag);
3193 autoscroll_timeout_tag = -1;
3198 Editor::convert_drop_to_paths (vector<string>& paths,
3199 GdkDragContext *context,
3202 GtkSelectionData *data,
3210 gchar *tname = gdk_atom_name (data->type);
3212 if (session == 0 || strcmp (tname, "text/plain") != 0) {
3216 /* Parse the "uri-list" format that Nautilus provides,
3217 where each pathname is delimited by \r\n
3220 path = (char *) data->data;
3223 for (int n = 0; n < data->length; ++n) {
3227 if (path[n] == '\r') {
3234 if (path[n] == '\n') {
3235 paths.push_back (spath);
3239 warning << _("incorrectly formatted URI list, ignored")
3247 /* nautilus and presumably some other file managers prefix even text/plain with file:// */
3249 for (vector<string>::iterator p = paths.begin(); p != paths.end(); ++p) {
3251 // cerr << "dropped text was " << *p << endl;
3255 // cerr << "decoded was " << *p << endl;
3257 if ((*p).substr (0,7) == "file://") {
3258 (*p) = (*p).substr (7);
3266 Editor::track_canvas_drag_data_received (GdkDragContext *context,
3269 GtkSelectionData *data,
3274 AudioTimeAxisView* tv;
3276 vector<string> paths;
3279 jack_nframes_t frame;
3281 if (convert_drop_to_paths (paths, context, x, y, data, info, time)) {
3285 /* D-n-D coordinates are window-relative, so convert to "world" coordinates
3291 track_canvas.c2w( x, y, wx, wy);
3293 ev.type = GDK_BUTTON_RELEASE;
3297 frame = event_frame (&ev, 0, &cy);
3301 if ((tvp = trackview_by_y_position (cy)) == 0) {
3303 /* drop onto canvas background: create a new track */
3305 insert_paths_as_new_tracks (paths, false);
3308 } else if ((tv = dynamic_cast<AudioTimeAxisView*>(tvp)) != 0) {
3310 /* check that its an audio track, not a bus */
3312 if (tv->get_diskstream()) {
3314 for (vector<string>::iterator p = paths.begin(); p != paths.end(); ++p) {
3315 insert_sndfile_into (*p, true, tv, frame);
3322 gtk_drag_finish (context, TRUE, FALSE, time);
3326 Editor::new_tempo_section ()
3332 Editor::map_transport_state ()
3334 ENSURE_GUI_THREAD (mem_fun(*this, &Editor::map_transport_state));
3336 if (session->transport_stopped()) {
3337 have_pending_keyboard_selection = false;
3343 Editor::State::State ()
3345 selection = new Selection;
3348 Editor::State::~State ()
3354 Editor::get_memento () const
3356 State *state = new State;
3358 store_state (*state);
3359 return bind (mem_fun (*(const_cast<Editor*>(this)), &Editor::restore_state), state);
3363 Editor::store_state (State& state) const
3365 *state.selection = *selection;
3369 Editor::restore_state (State *state)
3371 if (*selection == *state->selection) {
3375 *selection = *state->selection;
3376 time_selection_changed ();
3377 region_selection_changed ();
3379 /* XXX other selection change handlers? */
3383 Editor::begin_reversible_command (string name)
3386 UndoAction ua = get_memento();
3387 session->begin_reversible_command (name, &ua);
3392 Editor::commit_reversible_command ()
3395 UndoAction ua = get_memento();
3396 session->commit_reversible_command (&ua);
3401 Editor::flush_track_canvas ()
3403 /* I don't think this is necessary, and only causes more problems.
3404 I'm commenting it out
3405 and if the imageframe folks don't have any issues, we can take
3406 out this method entirely
3409 //gnome_canvas_update_now (GNOME_CANVAS(track_canvas));
3410 //gtk_main_iteration ();
3414 Editor::set_selected_track_from_click (bool add, bool with_undo, bool no_remove)
3416 if (!clicked_trackview) {
3421 begin_reversible_command (_("set selected trackview"));
3426 if (selection->selected (clicked_trackview)) {
3428 selection->remove (clicked_trackview);
3431 selection->add (clicked_trackview);
3436 if (selection->selected (clicked_trackview) && selection->tracks.size() == 1) {
3437 /* no commit necessary */
3441 selection->set (clicked_trackview);
3445 commit_reversible_command ();
3450 Editor::set_selected_control_point_from_click (bool add, bool with_undo, bool no_remove)
3452 if (!clicked_control_point) {
3457 begin_reversible_command (_("set selected control point"));
3467 commit_reversible_command ();
3472 Editor::set_selected_regionview_from_click (bool add, bool no_track_remove)
3474 if (!clicked_regionview) {
3478 AudioTimeAxisView* atv = dynamic_cast<AudioTimeAxisView*>(&clicked_regionview->get_time_axis_view());
3484 RouteGroup* group = atv->route().edit_group();
3485 vector<AudioRegionView*> all_equivalent_regions;
3487 if (group && group->is_active()) {
3489 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
3491 AudioTimeAxisView* tatv;
3493 if ((tatv = dynamic_cast<AudioTimeAxisView*> (*i)) != 0) {
3495 if (tatv->route().edit_group() != group) {
3500 vector<AudioRegion*> results;
3501 AudioRegionView* marv;
3504 if ((ds = tatv->get_diskstream()) == 0) {
3509 if ((pl = ds->playlist()) != 0) {
3510 pl->get_equivalent_regions (clicked_regionview->region,
3514 for (vector<AudioRegion*>::iterator ir = results.begin(); ir != results.end(); ++ir) {
3515 if ((marv = tatv->view->find_view (**ir)) != 0) {
3516 all_equivalent_regions.push_back (marv);
3525 all_equivalent_regions.push_back (clicked_regionview);
3529 begin_reversible_command (_("set selected regionview"));
3533 if (clicked_regionview->get_selected()) {
3534 if (group && group->is_active() && selection->audio_regions.size() > 1) {
3535 /* reduce selection down to just the one clicked */
3536 selection->set (clicked_regionview);
3538 selection->remove (clicked_regionview);
3541 selection->add (all_equivalent_regions);
3544 set_selected_track_from_click (add, false, no_track_remove);
3548 // karsten wiese suggested these two lines to make
3549 // a selected region rise to the top. but this
3550 // leads to a mismatch between actual layering
3551 // and visual layering. resolution required ....
3553 // gnome_canvas_item_raise_to_top (clicked_regionview->get_canvas_group());
3554 // gnome_canvas_item_raise_to_top (clicked_regionview->get_time_axis_view().canvas_display);
3556 if (clicked_regionview->get_selected()) {
3557 /* no commit necessary: we are the one selected. */
3562 selection->set (all_equivalent_regions);
3563 set_selected_track_from_click (add, false, false);
3567 commit_reversible_command () ;
3571 Editor::set_selected_regionview_from_region_list (Region& r, bool add)
3573 vector<AudioRegionView*> all_equivalent_regions;
3574 AudioRegion* region;
3576 if ((region = dynamic_cast<AudioRegion*>(&r)) == 0) {
3580 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
3582 AudioTimeAxisView* tatv;
3584 if ((tatv = dynamic_cast<AudioTimeAxisView*> (*i)) != 0) {
3587 vector<AudioRegion*> results;
3588 AudioRegionView* marv;
3591 if ((ds = tatv->get_diskstream()) == 0) {
3596 if ((pl = ds->playlist()) != 0) {
3597 pl->get_region_list_equivalent_regions (*region, results);
3600 for (vector<AudioRegion*>::iterator ir = results.begin(); ir != results.end(); ++ir) {
3601 if ((marv = tatv->view->find_view (**ir)) != 0) {
3602 all_equivalent_regions.push_back (marv);
3609 begin_reversible_command (_("set selected regions"));
3613 selection->add (all_equivalent_regions);
3617 selection->set (all_equivalent_regions);
3620 commit_reversible_command () ;
3624 Editor::set_selected_regionview_from_map_event (GdkEventAny* ev, StreamView* sv, Region* r)
3626 AudioRegionView* rv;
3629 if ((ar = dynamic_cast<AudioRegion*> (r)) == 0) {
3633 if ((rv = sv->find_view (*ar)) == 0) {
3637 /* don't reset the selection if its something other than
3638 a single other region.
3641 if (selection->audio_regions.size() > 1) {
3645 begin_reversible_command (_("set selected regions"));
3647 selection->set (rv);
3649 commit_reversible_command () ;
3655 Editor::set_edit_group_solo (Route& route, bool yn)
3657 RouteGroup *edit_group;
3659 if ((edit_group = route.edit_group()) != 0) {
3660 edit_group->apply (&Route::set_solo, yn, this);
3662 route.set_solo (yn, this);
3667 Editor::set_edit_group_mute (Route& route, bool yn)
3669 RouteGroup *edit_group = 0;
3671 if ((edit_group == route.edit_group()) != 0) {
3672 edit_group->apply (&Route::set_mute, yn, this);
3674 route.set_mute (yn, this);
3679 Editor::set_edit_menu (Menu& menu)
3682 edit_menu->signal_map_event().connect (mem_fun(*this, &Editor::edit_menu_map_handler));
3686 Editor::edit_menu_map_handler (GdkEventAny* ev)
3688 using namespace Menu_Helpers;
3689 MenuList& edit_items = edit_menu->items();
3692 /* Nuke all the old items */
3694 edit_items.clear ();
3700 if (session->undo_depth() == 0) {
3703 label = string_compose(_("Undo (%1)"), session->next_undo());
3706 edit_items.push_back (MenuElem (label, bind (mem_fun(*this, &Editor::undo), 1U)));
3708 if (session->undo_depth() == 0) {
3709 edit_items.back().set_sensitive (false);
3712 if (session->redo_depth() == 0) {
3715 label = string_compose(_("Redo (%1)"), session->next_redo());
3718 edit_items.push_back (MenuElem (label, bind (mem_fun(*this, &Editor::redo), 1U)));
3719 if (session->redo_depth() == 0) {
3720 edit_items.back().set_sensitive (false);
3723 vector<MenuItem*> mitems;
3725 edit_items.push_back (SeparatorElem());
3726 edit_items.push_back (MenuElem (_("Cut"), mem_fun(*this, &Editor::cut)));
3727 mitems.push_back (&edit_items.back());
3728 edit_items.push_back (MenuElem (_("Copy"), mem_fun(*this, &Editor::copy)));
3729 mitems.push_back (&edit_items.back());
3730 edit_items.push_back (MenuElem (_("Paste"), bind (mem_fun(*this, &Editor::paste), 1.0f)));
3731 mitems.push_back (&edit_items.back());
3732 edit_items.push_back (SeparatorElem());
3733 edit_items.push_back (MenuElem (_("Align"), bind (mem_fun(*this, &Editor::align), ARDOUR::SyncPoint)));
3734 mitems.push_back (&edit_items.back());
3735 edit_items.push_back (MenuElem (_("Align Relative"), bind (mem_fun(*this, &Editor::align_relative), ARDOUR::SyncPoint)));
3736 mitems.push_back (&edit_items.back());
3737 edit_items.push_back (SeparatorElem());
3739 if (selection->empty()) {
3740 for (vector<MenuItem*>::iterator i = mitems.begin(); i != mitems.end(); ++i) {
3741 (*i)->set_sensitive (false);
3745 Menu* import_menu = manage (new Menu());
3746 import_menu->set_name ("ArdourContextMenu");
3747 MenuList& import_items = import_menu->items();
3749 import_items.push_back (MenuElem (_("... as new track"), bind (mem_fun(*this, &Editor::import_audio), true)));
3750 import_items.push_back (MenuElem (_("... as new region"), bind (mem_fun(*this, &Editor::import_audio), false)));
3752 Menu* embed_menu = manage (new Menu());
3753 embed_menu->set_name ("ArdourContextMenu");
3754 MenuList& embed_items = embed_menu->items();
3756 embed_items.push_back (MenuElem (_("... as new track"), bind (mem_fun(*this, &Editor::insert_sndfile), true)));
3757 embed_items.push_back (MenuElem (_("... as new region"), mem_fun(*this, &Editor::embed_audio)));
3759 edit_items.push_back (MenuElem (_("Import audio (copy)"), *import_menu));
3760 edit_items.push_back (MenuElem (_("Embed audio (link)"), *embed_menu));
3761 edit_items.push_back (SeparatorElem());
3763 edit_items.push_back (MenuElem (_("Remove last capture"), mem_fun(*this, &Editor::remove_last_capture)));
3764 if (!session->have_captured()) {
3765 edit_items.back().set_sensitive (false);
3772 Editor::duplicate_dialog (bool dup_region)
3775 if (clicked_regionview == 0) {
3779 if (selection->time.length() == 0) {
3784 ArdourDialog win ("duplicate dialog");
3786 Label label (_("Duplicate how many times?"));
3789 Button ok_button (_("OK"));
3790 Button cancel_button (_("Cancel"));
3793 button_box.set_spacing (7);
3794 set_size_request_to_display_given_text (ok_button, _("Cancel"), 20, 15); // this is cancel on purpose
3795 set_size_request_to_display_given_text (cancel_button, _("Cancel"), 20, 15);
3796 button_box.pack_end (ok_button, false, false);
3797 button_box.pack_end (cancel_button, false, false);
3799 hbox.set_spacing (5);
3800 hbox.pack_start (label);
3801 hbox.pack_start (entry, true, true);
3803 vbox.set_spacing (5);
3804 vbox.set_border_width (5);
3805 vbox.pack_start (hbox);
3806 vbox.pack_start (button_box);
3809 win.set_position (Gtk::WIN_POS_MOUSE);
3812 ok_button.signal_clicked().connect (bind (mem_fun (win, &ArdourDialog::stop), 0));
3813 entry.signal_activate().connect (bind (mem_fun (win, &ArdourDialog::stop), 0));
3814 cancel_button.signal_clicked().connect (bind (mem_fun (win, &ArdourDialog::stop), 1));
3816 entry.signal_focus_in_event().connect (sigc::ptr_fun (ARDOUR_UI::generic_focus_in_event));
3817 entry.signal_focus_out_event().connect (sigc::ptr_fun (ARDOUR_UI::generic_focus_out_event));
3819 entry.set_text ("1");
3820 set_size_request_to_display_given_text (entry, X_("12345678"), 20, 15);
3821 entry.select_region (0, entry.get_text_length());
3823 win.set_position (Gtk::WIN_POS_MOUSE);
3826 // win.get_window()->set_decorations (Gdk::WMDecoration (Gdk::DECOR_BORDER|Gdk::DECOR_RESIZEH));
3828 entry.grab_focus ();
3832 if (win.run_status() != 0) {
3836 string text = entry.get_text();
3839 if (sscanf (text.c_str(), "%f", ×) == 1) {
3841 AudioRegionSelection regions;
3842 regions.add (clicked_regionview);
3843 duplicate_some_regions (regions, times);
3845 duplicate_selection (times);
3851 Editor::show_verbose_canvas_cursor ()
3853 verbose_canvas_cursor->raise_to_top();
3854 verbose_canvas_cursor->show();
3855 verbose_cursor_visible = true;
3859 Editor::hide_verbose_canvas_cursor ()
3861 verbose_canvas_cursor->hide();
3862 verbose_cursor_visible = false;
3866 Editor::set_verbose_canvas_cursor (string txt, double x, double y)
3868 /* XXX get origin of canvas relative to root window,
3869 add x and y and check compared to gdk_screen_{width,height}
3871 verbose_canvas_cursor->set_property("text", txt.c_str());
3872 verbose_canvas_cursor->set_property("x", x);
3873 verbose_canvas_cursor->set_property("y", y);
3877 Editor::set_verbose_canvas_cursor_text (string txt)
3879 verbose_canvas_cursor->set_property("text", txt.c_str());
3883 Editor::edit_mode_selection_done ()
3889 string choice = edit_mode_selector.get_active_text();
3890 EditMode mode = Slide;
3892 if (choice == _("Splice")) {
3894 } else if (choice == _("Slide")) {
3898 session->set_edit_mode (mode);
3902 Editor::snap_type_selection_done ()
3908 string choice = snap_type_selector.get_active_text();
3909 SnapType snaptype = SnapToFrame;
3911 if (choice == _("Beats/3")) {
3912 snaptype = SnapToAThirdBeat;
3913 } else if (choice == _("Beats/4")) {
3914 snaptype = SnapToAQuarterBeat;
3915 } else if (choice == _("Beats/8")) {
3916 snaptype = SnapToAEighthBeat;
3917 } else if (choice == _("Beats/16")) {
3918 snaptype = SnapToASixteenthBeat;
3919 } else if (choice == _("Beats/32")) {
3920 snaptype = SnapToAThirtysecondBeat;
3921 } else if (choice == _("Beats")) {
3922 snaptype = SnapToBeat;
3923 } else if (choice == _("Bars")) {
3924 snaptype = SnapToBar;
3925 } else if (choice == _("Marks")) {
3926 snaptype = SnapToMark;
3927 } else if (choice == _("Edit Cursor")) {
3928 snaptype = SnapToEditCursor;
3929 } else if (choice == _("Region starts")) {
3930 snaptype = SnapToRegionStart;
3931 } else if (choice == _("Region ends")) {
3932 snaptype = SnapToRegionEnd;
3933 } else if (choice == _("Region bounds")) {
3934 snaptype = SnapToRegionBoundary;
3935 } else if (choice == _("Region syncs")) {
3936 snaptype = SnapToRegionSync;
3937 } else if (choice == _("CD Frames")) {
3938 snaptype = SnapToCDFrame;
3939 } else if (choice == _("SMPTE Frames")) {
3940 snaptype = SnapToSMPTEFrame;
3941 } else if (choice == _("SMPTE Seconds")) {
3942 snaptype = SnapToSMPTESeconds;
3943 } else if (choice == _("SMPTE Minutes")) {
3944 snaptype = SnapToSMPTEMinutes;
3945 } else if (choice == _("Seconds")) {
3946 snaptype = SnapToSeconds;
3947 } else if (choice == _("Minutes")) {
3948 snaptype = SnapToMinutes;
3949 } else if (choice == _("None")) {
3950 snaptype = SnapToFrame;
3953 set_snap_to (snaptype);
3957 Editor::snap_mode_selection_done ()
3963 string choice = snap_mode_selector.get_active_text();
3964 SnapMode mode = SnapNormal;
3966 if (choice == _("Normal")) {
3968 } else if (choice == _("Magnetic")) {
3969 mode = SnapMagnetic;
3972 set_snap_mode (mode);
3976 Editor::zoom_focus_selection_done ()
3982 string choice = zoom_focus_selector.get_active_text();
3983 ZoomFocus focus_type = ZoomFocusLeft;
3985 if (choice == _("Left")) {
3986 focus_type = ZoomFocusLeft;
3987 } else if (choice == _("Right")) {
3988 focus_type = ZoomFocusRight;
3989 } else if (choice == _("Center")) {
3990 focus_type = ZoomFocusCenter;
3991 } else if (choice == _("Playhead")) {
3992 focus_type = ZoomFocusPlayhead;
3993 } else if (choice == _("Edit Cursor")) {
3994 focus_type = ZoomFocusEdit;
3997 set_zoom_focus (focus_type);
4001 Editor::edit_controls_button_release (GdkEventButton* ev)
4003 if (Keyboard::is_context_menu_event (ev)) {
4004 ARDOUR_UI::instance()->add_route ();
4010 Editor::track_selection_changed ()
4012 switch (selection->tracks.size()){
4016 set_selected_mixer_strip (*(selection->tracks.front()));
4020 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
4021 (*i)->set_selected (false);
4022 if (mouse_mode == MouseRange) {
4023 (*i)->hide_selection ();
4027 for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
4028 (*i)->set_selected (true);
4029 if (mouse_mode == MouseRange) {
4030 (*i)->show_selection (selection->time);
4036 Editor::time_selection_changed ()
4038 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
4039 (*i)->hide_selection ();
4042 if (selection->tracks.empty()) {
4043 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
4044 (*i)->show_selection (selection->time);
4047 for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
4048 (*i)->show_selection (selection->time);
4054 Editor::region_selection_changed ()
4056 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
4057 (*i)->set_selected_regionviews (selection->audio_regions);
4062 Editor::point_selection_changed ()
4064 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
4065 (*i)->set_selected_points (selection->points);
4070 Editor::run_sub_event_loop ()
4072 Keyboard::the_keyboard().allow_focus (true);
4073 sub_event_loop_status = 0;
4078 Editor::finish_sub_event_loop (int status)
4081 Keyboard::the_keyboard().allow_focus (false);
4082 sub_event_loop_status = status;
4086 Editor::finish_sub_event_loop_on_delete (GdkEventAny *ignored, int32_t status)
4088 finish_sub_event_loop (status);
4093 Editor::mouse_select_button_release (GdkEventButton* ev)
4095 /* this handles just right-clicks */
4097 if (ev->button != 3) {
4104 Editor::TrackViewList *
4105 Editor::get_valid_views (TimeAxisView* track, RouteGroup* group)
4108 TrackViewList::iterator i;
4110 v = new TrackViewList;
4112 if (track == 0 && group == 0) {
4116 for (i = track_views.begin(); i != track_views.end (); ++i) {
4120 } else if (track != 0 && group == 0 || (track != 0 && group != 0 && !group->is_active())) {
4122 /* just the view for this track
4125 v->push_back (track);
4129 /* views for all tracks in the edit group */
4131 for (i = track_views.begin(); i != track_views.end (); ++i) {
4133 if (group == 0 || (*i)->edit_group() == group) {
4143 Editor::set_zoom_focus (ZoomFocus f)
4145 if (zoom_focus != f) {
4147 vector<string> txt = internationalize (zoom_focus_strings);
4148 zoom_focus_selector.set_active_text (txt[(int)f]);
4149 ZoomFocusChanged (); /* EMIT_SIGNAL */
4156 Editor::ensure_float (Window& win)
4158 win.set_transient_for (*this);
4162 Editor::pane_allocation_handler (Gtk::Allocation &alloc, Gtk::Paned* which)
4164 /* recover or initialize pane positions. do this here rather than earlier because
4165 we don't want the positions to change the child allocations, which they seem to do.
4171 XMLNode* node = ARDOUR_UI::instance()->editor_settings();
4173 static int32_t done[4] = { 0, 0, 0, 0 };
4176 if ((geometry = find_named_node (*node, "geometry")) == 0) {
4177 width = default_width;
4178 height = default_height;
4180 width = atoi(geometry->property("x_size")->value());
4181 height = atoi(geometry->property("y_size")->value());
4184 if (which == static_cast<Gtk::Paned*> (&track_list_canvas_pane)) {
4190 if (!geometry || (prop = geometry->property("track_list_canvas_pane_pos")) == 0) {
4192 snprintf (buf, sizeof(buf), "%d", pos);
4194 pos = atoi (prop->value());
4197 if ((done[0] = GTK_WIDGET(track_list_canvas_pane.gobj())->allocation.width > pos)) {
4198 track_list_canvas_pane.set_position (pos);
4201 } else if (which == static_cast<Gtk::Paned*> (&canvas_region_list_pane)) {
4207 if (!geometry || (prop = geometry->property("canvas_region_list_pane_pos")) == 0) {
4208 pos = width - (95 * 2);
4209 snprintf (buf, sizeof(buf), "%d", pos);
4211 pos = atoi (prop->value());
4214 if ((done[1] = GTK_WIDGET(canvas_region_list_pane.gobj())->allocation.width > pos)) {
4215 canvas_region_list_pane.set_position (pos);
4218 } else if (which == static_cast<Gtk::Paned*> (&route_group_vpane)) {
4224 if (!geometry || (prop = geometry->property("route_group_pane_pos")) == 0) {
4225 pos = width - (95 * 2);
4226 snprintf (buf, sizeof(buf), "%d", pos);
4228 pos = atoi (prop->value());
4231 if ((done[2] = GTK_WIDGET(route_group_vpane.gobj())->allocation.height > pos)) {
4232 route_group_vpane.set_position (pos);
4235 } else if (which == static_cast<Gtk::Paned*> (®ion_selection_vpane)) {
4241 if (!geometry || (prop = geometry->property("region_selection_pane_pos")) == 0) {
4242 pos = width - (95 * 2);
4243 snprintf (buf, sizeof(buf), "%d", pos);
4245 pos = atoi (prop->value());
4248 if ((done[3] = GTK_WIDGET(region_selection_vpane.gobj())->allocation.height > pos)) {
4249 region_selection_vpane.set_position (pos);
4255 Editor::detach_tearoff (Gtk::Box* b, Gtk::Window* w)
4257 if (tools_tearoff->torn_off() &&
4258 mouse_mode_tearoff->torn_off()) {
4259 top_hbox.remove (toolbar_frame);
4266 Editor::reattach_tearoff (Gtk::Box* b, Gtk::Window* w, int32_t n)
4268 if (toolbar_frame.get_parent() == 0) {
4269 top_hbox.pack_end (toolbar_frame);
4274 Editor::set_show_measures (bool yn)
4276 if (_show_measures != yn) {
4279 if ((_show_measures = yn) == true) {
4282 DisplayControlChanged (ShowMeasures);
4288 Editor::set_follow_playhead (bool yn)
4290 if (_follow_playhead != yn) {
4291 if ((_follow_playhead = yn) == true) {
4293 update_current_screen ();
4295 DisplayControlChanged (FollowPlayhead);
4301 Editor::toggle_xfade_active (Crossfade* xfade)
4303 xfade->set_active (!xfade->active());
4307 Editor::toggle_xfade_length (Crossfade* xfade)
4309 xfade->set_follow_overlap (!xfade->following_overlap());
4313 Editor::edit_xfade (Crossfade* xfade)
4315 CrossfadeEditor cew (*session, *xfade, xfade->fade_in().get_min_y(), 1.0);
4319 cew.ok_button.signal_clicked().connect (bind (mem_fun (cew, &ArdourDialog::stop), 1));
4320 cew.cancel_button.signal_clicked().connect (bind (mem_fun (cew, &ArdourDialog::stop), 0));
4322 // cew.signal_delete_event().connect (mem_fun (cew, &ArdourDialog::wm_doi_event_stop));
4326 if (cew.run_status() == 1) {
4328 xfade->StateChanged (Change (~0));
4333 Editor::playlist_selector () const
4335 return *_playlist_selector;
4339 Editor::get_nudge_distance (jack_nframes_t pos, jack_nframes_t& next)
4343 ret = nudge_clock.current_duration (pos);
4344 next = ret + 1; /* XXXX fix me */
4350 Editor::end_location_changed (Location* location)
4352 ENSURE_GUI_THREAD (bind (mem_fun(*this, &Editor::end_location_changed), location));
4353 track_canvas_scroller.get_hadjustment()->set_upper (location->end() / frames_per_unit);
4357 Editor::playlist_deletion_dialog (Playlist* pl)
4359 ArdourDialog dialog ("playlist deletion dialog");
4360 Label label (string_compose (_("Playlist %1 is currently unused.\n"
4361 "If left alone, no audio files used by it will be cleaned.\n"
4362 "If deleted, audio files used by it alone by will cleaned."),
4365 Button del_button (_("Delete playlist"));
4366 Button keep_button (_("Keep playlist"));
4367 Button abort_button (_("Cancel cleanup"));
4370 button_box.set_spacing (7);
4371 button_box.set_homogeneous (true);
4372 button_box.pack_end (del_button, false, false);
4373 button_box.pack_end (keep_button, false, false);
4374 button_box.pack_end (abort_button, false, false);
4376 vbox.set_spacing (5);
4377 vbox.set_border_width (5);
4378 vbox.pack_start (label);
4379 vbox.pack_start (button_box);
4382 dialog.set_position (Gtk::WIN_POS_CENTER);
4385 del_button.signal_clicked().connect (bind (mem_fun (dialog, &ArdourDialog::stop), 0));
4386 keep_button.signal_clicked().connect (bind (mem_fun (dialog, &ArdourDialog::stop), 1));
4387 abort_button.signal_clicked().connect (bind (mem_fun (dialog, &ArdourDialog::stop), 2));
4390 // dialog.realize ();
4391 // dialog.get_window()->set_decorations (Gdk::WMDecoration (Gdk::DECOR_BORDER|Gdk::DECOR_RESIZEH));
4395 switch (dialog.run_status()) {
4397 /* keep the playlist */
4401 /* delete the playlist */
4409 /* keep the playlist */
4415 Editor::audio_region_selection_covers (jack_nframes_t where)
4417 for (AudioRegionSelection::iterator a = selection->audio_regions.begin(); a != selection->audio_regions.end(); ++a) {
4418 if ((*a)->region.covers (where)) {
4427 Editor::prepare_for_cleanup ()
4429 cut_buffer->clear_audio_regions ();
4430 cut_buffer->clear_playlists ();
4432 selection->clear_audio_regions ();
4433 selection->clear_playlists ();
4437 Editor::init_colormap ()
4439 for (size_t x = 0; x < sizeof (color_id_strs) / sizeof (color_id_strs[0]); ++x) {
4440 pair<ColorID,int> newpair;
4442 newpair.first = (ColorID) x;
4443 newpair.second = rgba_from_style (enum2str (newpair.first), 0, 0, 0, 255);
4444 color_map.insert (newpair);
4449 Editor::transport_loop_location()
4452 return session->locations()->auto_loop_location();
4459 Editor::transport_punch_location()
4462 return session->locations()->auto_punch_location();