2 Copyright (C) 2000-2007 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.
20 /* Note: public Editor methods are documented in public_editor.h */
28 #include <sigc++/bind.h>
30 #include <pbd/convert.h>
31 #include <pbd/error.h>
32 #include <pbd/enumwriter.h>
33 #include <pbd/memento_command.h>
35 #include <glibmm/miscutils.h>
36 #include <gtkmm/image.h>
37 #include <gdkmm/color.h>
38 #include <gdkmm/bitmap.h>
40 #include <gtkmm2ext/grouped_buttons.h>
41 #include <gtkmm2ext/gtk_ui.h>
42 #include <gtkmm2ext/tearoff.h>
43 #include <gtkmm2ext/utils.h>
44 #include <gtkmm2ext/window_title.h>
45 #include <gtkmm2ext/choice.h>
47 #include <ardour/audio_track.h>
48 #include <ardour/audio_diskstream.h>
49 #include <ardour/plugin_manager.h>
50 #include <ardour/location.h>
51 #include <ardour/audioplaylist.h>
52 #include <ardour/audioregion.h>
53 #include <ardour/midi_region.h>
54 #include <ardour/session_route.h>
55 #include <ardour/tempo.h>
56 #include <ardour/utils.h>
58 #include <control_protocol/control_protocol.h>
60 #include "ardour_ui.h"
64 #include "playlist_selector.h"
65 #include "audio_region_view.h"
66 #include "rgb_macros.h"
67 #include "selection.h"
68 #include "audio_streamview.h"
69 #include "time_axis_view.h"
70 #include "audio_time_axis.h"
72 #include "crossfade_view.h"
74 #include "public_editor.h"
75 #include "crossfade_edit.h"
76 #include "canvas_impl.h"
78 #include "gui_thread.h"
81 #include "analysis_window.h"
87 #include "imageframe_socket_handler.h"
92 using namespace ARDOUR;
96 using namespace Gtkmm2ext;
97 using namespace Editing;
99 using PBD::internationalize;
102 const double Editor::timebar_height = 15.0;
104 #include "editor_xpms"
106 static const gchar *_snap_type_strings[] = {
130 static const gchar *_snap_mode_strings[] = {
136 static const gchar *_zoom_focus_strings[] = {
145 /* Soundfile drag-n-drop */
147 Gdk::Cursor* Editor::cross_hair_cursor = 0;
148 Gdk::Cursor* Editor::selector_cursor = 0;
149 Gdk::Cursor* Editor::trimmer_cursor = 0;
150 Gdk::Cursor* Editor::grabber_cursor = 0;
151 Gdk::Cursor* Editor::zoom_cursor = 0;
152 Gdk::Cursor* Editor::time_fx_cursor = 0;
153 Gdk::Cursor* Editor::fader_cursor = 0;
154 Gdk::Cursor* Editor::speaker_cursor = 0;
155 Gdk::Cursor* Editor::midi_select_cursor = 0;
156 Gdk::Cursor* Editor::midi_pencil_cursor = 0;
157 Gdk::Cursor* Editor::midi_erase_cursor = 0;
158 Gdk::Cursor* Editor::wait_cursor = 0;
159 Gdk::Cursor* Editor::timebar_cursor = 0;
162 show_me_the_size (Requisition* r, const char* what)
164 cerr << "size of " << what << " = " << r->width << " x " << r->height << endl;
168 check_adjustment (Gtk::Adjustment* adj)
170 cerr << "CHANGE adj = "
171 << adj->get_lower () << ' '
172 << adj->get_upper () << ' '
173 << adj->get_value () << ' '
174 << adj->get_step_increment () << ' '
175 << adj->get_page_increment () << ' '
176 << adj->get_page_size () << ' '
183 /* time display buttons */
185 minsec_label (_("Mins:Secs")),
186 bbt_label (_("Bars:Beats")),
187 smpte_label (_("Timecode")),
188 frame_label (_("Frames")),
189 tempo_label (_("Tempo")),
190 meter_label (_("Meter")),
191 mark_label (_("Location Markers")),
192 range_mark_label (_("Range Markers")),
193 transport_mark_label (_("Loop/Punch Ranges")),
195 edit_packer (3, 3, false),
197 /* the values here don't matter: layout widgets
198 reset them as needed.
201 vertical_adjustment (0.0, 0.0, 10.0, 400.0),
202 horizontal_adjustment (0.0, 0.0, 20.0, 1200.0),
205 marker_tempo_lines(0),
207 /* tool bar related */
209 edit_cursor_clock (X_("editcursor"), false, X_("EditCursorClock"), true),
210 zoom_range_clock (X_("zoomrange"), false, X_("ZoomRangeClock"), true, true),
212 toolbar_selection_clock_table (2,3),
214 automation_mode_button (_("mode")),
215 global_automation_button (_("automation")),
218 image_socket_listener(0),
223 nudge_clock (X_("nudge"), false, X_("NudgeClock"), true, true)
228 /* we are a singleton */
230 PublicEditor::_instance = this;
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_axisview = 0;
244 clicked_routeview = 0;
245 clicked_crossfadeview = 0;
246 clicked_control_point = 0;
247 latest_regionview = 0;
248 last_update_frame = 0;
250 current_mixer_strip = 0;
251 current_bbt_points = 0;
253 snap_type_strings = I18N (_snap_type_strings);
254 snap_mode_strings = I18N (_snap_mode_strings);
255 zoom_focus_strings = I18N(_zoom_focus_strings);
257 snap_type = SnapToFrame;
258 set_snap_to (snap_type);
259 snap_mode = SnapNormal;
260 set_snap_mode (snap_mode);
261 snap_threshold = 5.0;
262 bbt_beat_subdivision = 4;
265 autoscroll_active = false;
266 autoscroll_timeout_tag = -1;
267 interthread_progress_window = 0;
273 current_interthread_info = 0;
274 _show_measures = true;
275 _show_waveforms = true;
276 _show_waveforms_recording = true;
277 first_action_message = 0;
279 show_gain_after_trim = false;
280 ignore_route_list_reorder = false;
281 no_route_list_redisplay = false;
282 verbose_cursor_on = true;
283 route_removal = false;
284 show_automatic_regions_in_region_list = true;
285 region_list_sort_type = (Editing::RegionListSortType) 0;
286 have_pending_keyboard_selection = false;
287 _follow_playhead = true;
288 _xfade_visibility = true;
289 editor_ruler_menu = 0;
290 no_ruler_shown_update = false;
291 edit_group_list_menu = 0;
293 region_list_menu = 0;
295 start_end_marker_menu = 0;
296 range_marker_menu = 0;
297 marker_menu_item = 0;
299 transport_marker_menu = 0;
300 new_transport_marker_menu = 0;
301 editor_mixer_strip_width = Wide;
302 show_editor_mixer_when_tracks_arrive = false;
305 ignore_mouse_mode_toggle = false;
306 ignore_midi_edit_mode_toggle = false;
307 current_stepping_trackview = 0;
309 entered_regionview = 0;
310 clear_entered_track = false;
311 _new_regionviews_show_envelope = false;
312 current_timestretch = 0;
313 in_edit_group_row_change = false;
314 last_canvas_frame = 0;
317 button_release_can_deselect = true;
318 canvas_idle_queued = false;
319 _dragging_playhead = false;
320 _dragging_hscrollbar = false;
322 location_marker_color = ARDOUR_UI::config()->canvasvar_LocationMarker.get();
323 location_range_color = ARDOUR_UI::config()->canvasvar_LocationRange.get();
324 location_cd_marker_color = ARDOUR_UI::config()->canvasvar_LocationCDMarker.get();
325 location_loop_color = ARDOUR_UI::config()->canvasvar_LocationLoop.get();
326 location_punch_color = ARDOUR_UI::config()->canvasvar_LocationPunch.get();
328 range_marker_drag_rect = 0;
329 marker_drag_line = 0;
331 set_midi_edit_mode (MidiEditSelect, true);
332 set_mouse_mode (MouseObject, true);
334 frames_per_unit = 2048; /* too early to use reset_zoom () */
335 reset_hscrollbar_stepping ();
337 zoom_focus = ZoomFocusLeft;
338 set_zoom_focus (ZoomFocusLeft);
339 zoom_range_clock.ValueChanged.connect (mem_fun(*this, &Editor::zoom_adjustment_changed));
341 initialize_rulers ();
342 initialize_canvas ();
344 edit_controls_vbox.set_spacing (0);
345 horizontal_adjustment.signal_value_changed().connect (mem_fun(*this, &Editor::canvas_horizontally_scrolled));
346 vertical_adjustment.signal_value_changed().connect (mem_fun(*this, &Editor::tie_vertical_scrolling));
348 track_canvas.set_hadjustment (horizontal_adjustment);
349 track_canvas.set_vadjustment (vertical_adjustment);
350 time_canvas.set_hadjustment (horizontal_adjustment);
352 track_canvas.signal_map_event().connect (mem_fun (*this, &Editor::track_canvas_map_handler));
353 time_canvas.signal_map_event().connect (mem_fun (*this, &Editor::time_canvas_map_handler));
355 controls_layout.add (edit_controls_vbox);
356 controls_layout.set_name ("EditControlsBase");
357 controls_layout.add_events (Gdk::SCROLL_MASK);
358 controls_layout.signal_scroll_event().connect (mem_fun(*this, &Editor::control_layout_scroll), false);
360 controls_layout.add_events (Gdk::BUTTON_PRESS_MASK|Gdk::BUTTON_RELEASE_MASK|Gdk::ENTER_NOTIFY_MASK|Gdk::LEAVE_NOTIFY_MASK);
361 controls_layout.signal_button_release_event().connect (mem_fun(*this, &Editor::edit_controls_button_release));
362 controls_layout.signal_size_request().connect (mem_fun (*this, &Editor::controls_layout_size_request));
364 edit_vscrollbar.set_adjustment (vertical_adjustment);
365 edit_hscrollbar.set_adjustment (horizontal_adjustment);
367 edit_hscrollbar.signal_button_press_event().connect (mem_fun(*this, &Editor::hscrollbar_button_press), false);
368 edit_hscrollbar.signal_button_release_event().connect (mem_fun(*this, &Editor::hscrollbar_button_release), false);
369 edit_hscrollbar.signal_size_allocate().connect (mem_fun(*this, &Editor::hscrollbar_allocate));
371 edit_hscrollbar.set_name ("EditorHScrollbar");
375 setup_midi_toolbar ();
377 edit_cursor_clock.ValueChanged.connect (mem_fun(*this, &Editor::edit_cursor_clock_changed));
379 ArdourCanvas::Canvas* time_pad = manage(new ArdourCanvas::Canvas());
380 ArdourCanvas::SimpleLine* pad_line_1 = manage(new ArdourCanvas::SimpleLine(*time_pad->root(),
381 0.0, 1.0, 100.0, 1.0));
382 pad_line_1->property_color_rgba() = 0xFF0000FF;
386 time_canvas_vbox.pack_start (*_ruler_separator, false, false);
387 time_canvas_vbox.pack_start (*minsec_ruler, false, false);
388 time_canvas_vbox.pack_start (*smpte_ruler, false, false);
389 time_canvas_vbox.pack_start (*frames_ruler, false, false);
390 time_canvas_vbox.pack_start (*bbt_ruler, false, false);
391 time_canvas_vbox.pack_start (time_canvas, true, true);
392 time_canvas_vbox.set_size_request (-1, (int)(timebar_height * visible_timebars) + 5);
394 bbt_label.set_name ("EditorTimeButton");
395 bbt_label.set_size_request (-1, (int)timebar_height);
396 bbt_label.set_alignment (1.0, 0.5);
397 bbt_label.set_padding (5,0);
398 minsec_label.set_name ("EditorTimeButton");
399 minsec_label.set_size_request (-1, (int)timebar_height);
400 minsec_label.set_alignment (1.0, 0.5);
401 minsec_label.set_padding (5,0);
402 smpte_label.set_name ("EditorTimeButton");
403 smpte_label.set_size_request (-1, (int)timebar_height);
404 smpte_label.set_alignment (1.0, 0.5);
405 smpte_label.set_padding (5,0);
406 frame_label.set_name ("EditorTimeButton");
407 frame_label.set_size_request (-1, (int)timebar_height);
408 frame_label.set_alignment (1.0, 0.5);
409 frame_label.set_padding (5,0);
410 tempo_label.set_name ("EditorTimeButton");
411 tempo_label.set_size_request (-1, (int)timebar_height);
412 tempo_label.set_alignment (1.0, 0.5);
413 tempo_label.set_padding (5,0);
414 meter_label.set_name ("EditorTimeButton");
415 meter_label.set_size_request (-1, (int)timebar_height);
416 meter_label.set_alignment (1.0, 0.5);
417 meter_label.set_padding (5,0);
418 mark_label.set_name ("EditorTimeButton");
419 mark_label.set_size_request (-1, (int)timebar_height);
420 mark_label.set_alignment (1.0, 0.5);
421 mark_label.set_padding (5,0);
422 range_mark_label.set_name ("EditorTimeButton");
423 range_mark_label.set_size_request (-1, (int)timebar_height);
424 range_mark_label.set_alignment (1.0, 0.5);
425 range_mark_label.set_padding (5,0);
426 transport_mark_label.set_name ("EditorTimeButton");
427 transport_mark_label.set_size_request (-1, (int)timebar_height);
428 transport_mark_label.set_alignment (1.0, 0.5);
429 transport_mark_label.set_padding (5,0);
431 time_button_vbox.pack_start (minsec_label, false, false);
432 time_button_vbox.pack_start (smpte_label, false, false);
433 time_button_vbox.pack_start (frame_label, false, false);
434 time_button_vbox.pack_start (bbt_label, false, false);
435 time_button_vbox.pack_start (meter_label, false, false);
436 time_button_vbox.pack_start (tempo_label, false, false);
437 time_button_vbox.pack_start (mark_label, false, false);
439 time_button_event_box.add (time_button_vbox);
440 time_button_event_box.set_name ("TimebarLabelBase");
441 time_button_frame.set_shadow_type (Gtk::SHADOW_NONE);
443 time_button_event_box.set_events (Gdk::BUTTON_PRESS_MASK|Gdk::BUTTON_RELEASE_MASK);
444 time_button_event_box.signal_button_release_event().connect (mem_fun(*this, &Editor::ruler_label_button_release));
446 time_button_frame.add (time_button_event_box);
447 time_button_frame.set_name ("TimebarLabelBase");
448 time_button_frame.set_shadow_type (Gtk::SHADOW_ETCHED_OUT);
450 /* these enable us to have a dedicated window (for cursor setting, etc.)
451 for the canvas areas.
454 track_canvas_event_box.add (track_canvas);
456 time_canvas_event_box.add (time_canvas_vbox);
457 time_canvas_event_box.set_events (Gdk::BUTTON_PRESS_MASK|Gdk::BUTTON_RELEASE_MASK|Gdk::POINTER_MOTION_MASK);
459 edit_packer.set_col_spacings (0);
460 edit_packer.set_row_spacings (0);
461 edit_packer.set_homogeneous (false);
462 edit_packer.set_border_width (0);
463 edit_packer.set_name ("EditorWindow");
465 edit_packer.attach (edit_vscrollbar, 3, 4, 1, 2, FILL, FILL|EXPAND, 0, 0);
467 edit_packer.attach (time_button_frame, 0, 2, 0, 1, FILL, SHRINK, 0, 0);
468 edit_packer.attach (time_canvas_event_box, 2, 4, 0, 1, FILL|EXPAND, FILL, 0, 0);
470 edit_packer.attach (controls_layout, 1, 2, 1, 2, FILL, FILL|EXPAND, 0, 0);
471 edit_packer.attach (track_canvas_event_box, 2, 3, 1, 2, FILL|EXPAND, FILL|EXPAND, 0, 0);
473 edit_packer.attach (zoom_box, 1, 2, 2, 3, FILL, FILL, 0, 0);
474 edit_packer.attach (edit_hscrollbar, 2, 3, 2, 3, FILL|EXPAND, FILL, 0, 0);
476 bottom_hbox.set_border_width (2);
477 bottom_hbox.set_spacing (3);
479 route_display_model = ListStore::create(route_display_columns);
480 route_list_display.set_model (route_display_model);
481 route_list_display.append_column (_("Show"), route_display_columns.visible);
482 route_list_display.append_column (_("Name"), route_display_columns.text);
483 route_list_display.get_column (0)->set_data (X_("colnum"), GUINT_TO_POINTER(0));
484 route_list_display.get_column (1)->set_data (X_("colnum"), GUINT_TO_POINTER(1));
485 route_list_display.set_headers_visible (true);
486 route_list_display.set_name ("TrackListDisplay");
487 route_list_display.get_selection()->set_mode (SELECTION_NONE);
488 route_list_display.set_reorderable (true);
489 route_list_display.set_size_request (100,-1);
491 CellRendererToggle* route_list_visible_cell = dynamic_cast<CellRendererToggle*>(route_list_display.get_column_cell_renderer (0));
492 route_list_visible_cell->property_activatable() = true;
493 route_list_visible_cell->property_radio() = false;
495 route_display_model->signal_row_deleted().connect (mem_fun (*this, &Editor::route_list_delete));
496 route_display_model->signal_row_changed().connect (mem_fun (*this, &Editor::route_list_change));
498 route_list_display.signal_button_press_event().connect (mem_fun (*this, &Editor::route_list_display_button_press), false);
500 route_list_scroller.add (route_list_display);
501 route_list_scroller.set_policy (POLICY_NEVER, POLICY_AUTOMATIC);
503 group_model = ListStore::create(group_columns);
504 edit_group_display.set_model (group_model);
505 edit_group_display.append_column (_("Name"), group_columns.text);
506 edit_group_display.append_column (_("Active"), group_columns.is_active);
507 edit_group_display.append_column (_("Show"), group_columns.is_visible);
508 edit_group_display.get_column (0)->set_data (X_("colnum"), GUINT_TO_POINTER(0));
509 edit_group_display.get_column (1)->set_data (X_("colnum"), GUINT_TO_POINTER(1));
510 edit_group_display.get_column (2)->set_data (X_("colnum"), GUINT_TO_POINTER(2));
511 edit_group_display.get_column (0)->set_expand (true);
512 edit_group_display.get_column (1)->set_expand (false);
513 edit_group_display.get_column (2)->set_expand (false);
514 edit_group_display.set_headers_visible (true);
516 /* name is directly editable */
518 CellRendererText* name_cell = dynamic_cast<CellRendererText*>(edit_group_display.get_column_cell_renderer (0));
519 name_cell->property_editable() = true;
520 name_cell->signal_edited().connect (mem_fun (*this, &Editor::edit_group_name_edit));
522 /* use checkbox for the active + visible columns */
524 CellRendererToggle* active_cell = dynamic_cast<CellRendererToggle*>(edit_group_display.get_column_cell_renderer (1));
525 active_cell->property_activatable() = true;
526 active_cell->property_radio() = false;
528 active_cell = dynamic_cast<CellRendererToggle*>(edit_group_display.get_column_cell_renderer (1));
529 active_cell->property_activatable() = true;
530 active_cell->property_radio() = false;
532 group_model->signal_row_changed().connect (mem_fun (*this, &Editor::edit_group_row_change));
534 edit_group_display.set_name ("EditGroupList");
535 edit_group_display.get_selection()->set_mode (SELECTION_SINGLE);
536 edit_group_display.set_headers_visible (true);
537 edit_group_display.set_reorderable (false);
538 edit_group_display.set_rules_hint (true);
539 edit_group_display.set_size_request (75, -1);
541 edit_group_display_scroller.add (edit_group_display);
542 edit_group_display_scroller.set_policy (POLICY_AUTOMATIC, POLICY_AUTOMATIC);
544 edit_group_display.signal_button_press_event().connect (mem_fun(*this, &Editor::edit_group_list_button_press_event), false);
546 VBox* edit_group_display_packer = manage (new VBox());
547 HBox* edit_group_display_button_box = manage (new HBox());
548 edit_group_display_button_box->set_homogeneous (true);
550 Button* edit_group_add_button = manage (new Button ());
551 Button* edit_group_remove_button = manage (new Button ());
555 w = manage (new Image (Stock::ADD, ICON_SIZE_BUTTON));
557 edit_group_add_button->add (*w);
559 w = manage (new Image (Stock::REMOVE, ICON_SIZE_BUTTON));
561 edit_group_remove_button->add (*w);
563 edit_group_add_button->signal_clicked().connect (mem_fun (*this, &Editor::new_edit_group));
564 edit_group_remove_button->signal_clicked().connect (mem_fun (*this, &Editor::remove_selected_edit_group));
566 edit_group_display_button_box->pack_start (*edit_group_add_button);
567 edit_group_display_button_box->pack_start (*edit_group_remove_button);
569 edit_group_display_packer->pack_start (edit_group_display_scroller, true, true);
570 edit_group_display_packer->pack_start (*edit_group_display_button_box, false, false);
572 region_list_display.set_size_request (100, -1);
573 region_list_display.set_name ("RegionListDisplay");
575 region_list_model = TreeStore::create (region_list_columns);
576 region_list_model->set_sort_func (0, mem_fun (*this, &Editor::region_list_sorter));
577 region_list_model->set_sort_column (0, SORT_ASCENDING);
579 region_list_display.set_model (region_list_model);
580 region_list_display.append_column (_("Regions"), region_list_columns.name);
581 region_list_display.set_headers_visible (false);
583 region_list_display.get_selection()->set_select_function (mem_fun (*this, &Editor::region_list_selection_filter));
585 TreeViewColumn* tv_col = region_list_display.get_column(0);
586 CellRendererText* renderer = dynamic_cast<CellRendererText*>(region_list_display.get_column_cell_renderer (0));
587 tv_col->add_attribute(renderer->property_text(), region_list_columns.name);
588 tv_col->add_attribute(renderer->property_foreground_gdk(), region_list_columns.color_);
590 region_list_display.get_selection()->set_mode (SELECTION_MULTIPLE);
591 region_list_display.add_object_drag (region_list_columns.region.index(), "regions");
593 /* setup DnD handling */
595 list<TargetEntry> region_list_target_table;
597 region_list_target_table.push_back (TargetEntry ("text/plain"));
598 region_list_target_table.push_back (TargetEntry ("text/uri-list"));
599 region_list_target_table.push_back (TargetEntry ("application/x-rootwin-drop"));
601 region_list_display.add_drop_targets (region_list_target_table);
602 region_list_display.signal_drag_data_received().connect (mem_fun(*this, &Editor::region_list_display_drag_data_received));
604 region_list_scroller.add (region_list_display);
605 region_list_scroller.set_policy (POLICY_NEVER, POLICY_AUTOMATIC);
607 region_list_display.signal_key_press_event().connect (mem_fun(*this, &Editor::region_list_display_key_press));
608 region_list_display.signal_key_release_event().connect (mem_fun(*this, &Editor::region_list_display_key_release));
609 region_list_display.signal_button_press_event().connect (mem_fun(*this, &Editor::region_list_display_button_press), false);
610 region_list_display.signal_button_release_event().connect (mem_fun(*this, &Editor::region_list_display_button_release));
611 region_list_display.get_selection()->signal_changed().connect (mem_fun(*this, &Editor::region_list_selection_changed));
612 // region_list_display.signal_popup_menu().connect (bind (mem_fun (*this, &Editor::show_region_list_display_context_menu), 1, 0));
614 named_selection_scroller.add (named_selection_display);
615 named_selection_scroller.set_policy (POLICY_NEVER, POLICY_AUTOMATIC);
617 named_selection_model = TreeStore::create (named_selection_columns);
618 named_selection_display.set_model (named_selection_model);
619 named_selection_display.append_column (_("Chunks"), named_selection_columns.text);
620 named_selection_display.set_headers_visible (false);
621 named_selection_display.set_size_request (100, -1);
622 named_selection_display.set_name ("NamedSelectionDisplay");
624 named_selection_display.get_selection()->set_mode (SELECTION_SINGLE);
625 named_selection_display.set_size_request (100, -1);
626 named_selection_display.signal_button_release_event().connect (mem_fun(*this, &Editor::named_selection_display_button_release), false);
627 named_selection_display.signal_key_release_event().connect (mem_fun(*this, &Editor::named_selection_display_key_release), false);
628 named_selection_display.get_selection()->signal_changed().connect (mem_fun (*this, &Editor::named_selection_display_selection_changed));
632 snapshot_display_model = ListStore::create (snapshot_display_columns);
633 snapshot_display.set_model (snapshot_display_model);
634 snapshot_display.append_column (X_("snapshot"), snapshot_display_columns.visible_name);
635 snapshot_display.set_name ("SnapshotDisplay");
636 snapshot_display.set_size_request (75, -1);
637 snapshot_display.set_headers_visible (false);
638 snapshot_display.set_reorderable (false);
639 snapshot_display_scroller.add (snapshot_display);
640 snapshot_display_scroller.set_policy (Gtk::POLICY_NEVER, Gtk::POLICY_AUTOMATIC);
642 snapshot_display.get_selection()->signal_changed().connect (mem_fun(*this, &Editor::snapshot_display_selection_changed));
643 snapshot_display.signal_button_press_event().connect (mem_fun (*this, &Editor::snapshot_display_button_press), false);
647 nlabel = manage (new Label (_("Regions")));
648 nlabel->set_angle (-90);
649 the_notebook.append_page (region_list_scroller, *nlabel);
650 nlabel = manage (new Label (_("Tracks/Busses")));
651 nlabel->set_angle (-90);
652 the_notebook.append_page (route_list_scroller, *nlabel);
653 nlabel = manage (new Label (_("Snapshots")));
654 nlabel->set_angle (-90);
655 the_notebook.append_page (snapshot_display_scroller, *nlabel);
656 nlabel = manage (new Label (_("Edit Groups")));
657 nlabel->set_angle (-90);
658 the_notebook.append_page (*edit_group_display_packer, *nlabel);
659 nlabel = manage (new Label (_("Chunks")));
660 nlabel->set_angle (-90);
661 the_notebook.append_page (named_selection_scroller, *nlabel);
663 the_notebook.set_show_tabs (true);
664 the_notebook.set_scrollable (true);
665 the_notebook.popup_enable ();
666 the_notebook.set_tab_pos (Gtk::POS_RIGHT);
668 post_maximal_editor_width = 0;
669 post_maximal_pane_position = 0;
670 edit_pane.pack1 (edit_packer, true, true);
671 edit_pane.pack2 (the_notebook, false, true);
673 edit_pane.signal_size_allocate().connect (bind (mem_fun(*this, &Editor::pane_allocation_handler), static_cast<Paned*> (&edit_pane)));
675 top_hbox.pack_start (toolbar_frame, false, true);
676 top_hbox.pack_start (midi_toolbar_frame, false, true);
678 HBox *hbox = manage (new HBox);
679 hbox->pack_start (edit_pane, true, true);
681 global_vpacker.pack_start (top_hbox, false, false);
682 global_vpacker.pack_start (*hbox, true, true);
684 global_hpacker.pack_start (global_vpacker, true, true);
686 set_name ("EditorWindow");
687 add_accel_group (ActionManager::ui_manager->get_accel_group());
689 vpacker.pack_end (global_hpacker, true, true);
691 /* register actions now so that set_state() can find them and set toggles/checks etc */
695 XMLNode* node = ARDOUR_UI::instance()->editor_settings();
698 _playlist_selector = new PlaylistSelector();
699 _playlist_selector->signal_delete_event().connect (bind (sigc::ptr_fun (just_hide_it), static_cast<Window *> (_playlist_selector)));
701 RegionView::RegionViewGoingAway.connect (mem_fun(*this, &Editor::catch_vanishing_regionview));
705 nudge_forward_button.add (*(manage (new Image (::get_icon("nudge_right")))));
706 nudge_backward_button.add (*(manage (new Image (::get_icon("nudge_left")))));
708 ARDOUR_UI::instance()->tooltips().set_tip (nudge_forward_button, _("Nudge Region/Selection Forwards"));
709 ARDOUR_UI::instance()->tooltips().set_tip (nudge_backward_button, _("Nudge Region/Selection Backwards"));
711 nudge_forward_button.set_name ("TransportButton");
712 nudge_backward_button.set_name ("TransportButton");
714 fade_context_menu.set_name ("ArdourContextMenu");
716 /* icons, titles, WM stuff */
718 list<Glib::RefPtr<Gdk::Pixbuf> > window_icons;
719 Glib::RefPtr<Gdk::Pixbuf> icon;
721 if ((icon = ::get_icon ("ardour_icon_16px")) != 0) {
722 window_icons.push_back (icon);
724 if ((icon = ::get_icon ("ardour_icon_22px")) != 0) {
725 window_icons.push_back (icon);
727 if ((icon = ::get_icon ("ardour_icon_32px")) != 0) {
728 window_icons.push_back (icon);
730 if ((icon = ::get_icon ("ardour_icon_48px")) != 0) {
731 window_icons.push_back (icon);
733 if (!window_icons.empty()) {
734 set_icon_list (window_icons);
735 set_default_icon_list (window_icons);
738 WindowTitle title(Glib::get_application_name());
739 title += _("Editor");
740 set_title (title.get_string());
741 set_wmclass (X_("ardour_editor"), "Ardour");
744 add_events (Gdk::KEY_PRESS_MASK|Gdk::KEY_RELEASE_MASK);
746 signal_configure_event().connect (mem_fun (*ARDOUR_UI::instance(), &ARDOUR_UI::configure_handler));
747 signal_delete_event().connect (mem_fun (*ARDOUR_UI::instance(), &ARDOUR_UI::exit_on_main_window_close));
749 /* allow external control surfaces/protocols to do various things */
751 ControlProtocol::ZoomToSession.connect (mem_fun (*this, &Editor::temporal_zoom_session));
752 ControlProtocol::ZoomIn.connect (bind (mem_fun (*this, &Editor::temporal_zoom_step), false));
753 ControlProtocol::ZoomOut.connect (bind (mem_fun (*this, &Editor::temporal_zoom_step), true));
754 ControlProtocol::ScrollTimeline.connect (mem_fun (*this, &Editor::control_scroll));
756 Config->ParameterChanged.connect (mem_fun (*this, &Editor::parameter_changed));
765 if(image_socket_listener)
767 if(image_socket_listener->is_connected())
769 image_socket_listener->close_connection() ;
772 delete image_socket_listener ;
773 image_socket_listener = 0 ;
779 Editor::add_toplevel_controls (Container& cont)
781 vpacker.pack_start (cont, false, false);
786 Editor::catch_vanishing_regionview (RegionView *rv)
788 /* note: the selection will take care of the vanishing
789 audioregionview by itself.
792 if (clicked_regionview == rv) {
793 clicked_regionview = 0;
796 if (entered_regionview == rv) {
797 set_entered_regionview (0);
802 Editor::set_entered_regionview (RegionView* rv)
804 if (rv == entered_regionview) {
808 if (entered_regionview) {
809 entered_regionview->exited ();
812 if ((entered_regionview = rv) != 0) {
813 entered_regionview->entered ();
818 Editor::set_entered_track (TimeAxisView* tav)
821 entered_track->exited ();
824 if ((entered_track = tav) != 0) {
825 entered_track->entered ();
830 Editor::show_window ()
832 show_all_children ();
834 /* re-hide editor list if necessary */
835 editor_list_button_toggled ();
837 /* now reset all audio_time_axis heights, because widgets might need
843 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
844 tv = (static_cast<TimeAxisView*>(*i));
852 Editor::tie_vertical_scrolling ()
854 double y1 = vertical_adjustment.get_value();
855 controls_layout.get_vadjustment()->set_value (y1);
856 playhead_cursor->set_y_axis(y1);
857 edit_cursor->set_y_axis(y1);
861 Editor::instant_save ()
863 if (!constructed || !ARDOUR_UI::instance()->session_loaded) {
868 session->add_instant_xml(get_state());
870 Config->add_instant_xml(get_state());
875 Editor::edit_cursor_clock_changed()
877 if (edit_cursor->current_frame != edit_cursor_clock.current_time()) {
878 edit_cursor->set_position (edit_cursor_clock.current_time());
884 Editor::zoom_adjustment_changed ()
890 double fpu = zoom_range_clock.current_duration() / canvas_width;
894 zoom_range_clock.set ((nframes_t) floor (fpu * canvas_width));
895 } else if (fpu > session->current_end_frame() / canvas_width) {
896 fpu = session->current_end_frame() / canvas_width;
897 zoom_range_clock.set ((nframes_t) floor (fpu * canvas_width));
904 Editor::control_scroll (float fraction)
906 ENSURE_GUI_THREAD(bind (mem_fun (*this, &Editor::control_scroll), fraction));
912 double step = fraction * current_page_frames();
915 if ((fraction < 0.0f) && (session->transport_frame() < (nframes_t) fabs(step))) {
917 } else if ((fraction > 0.0f) && (max_frames - session->transport_frame() < step)) {
918 target = (max_frames - (current_page_frames()*2)); // allow room for slop in where the PH is on the screen
920 target = (session->transport_frame() + (nframes_t) floor ((fraction * current_page_frames())));
923 /* move visuals, we'll catch up with it later */
925 playhead_cursor->set_position (target);
927 if (target > (current_page_frames() / 2)) {
928 /* try to center PH in window */
929 reset_x_origin (target - (current_page_frames()/2));
934 /* cancel the existing */
936 control_scroll_connection.disconnect ();
938 /* add the next one */
940 control_scroll_connection = Glib::signal_timeout().connect (bind (mem_fun (*this, &Editor::deferred_control_scroll), target), 50);
944 Editor::deferred_control_scroll (nframes_t target)
946 session->request_locate (target);
951 Editor::on_realize ()
953 Window::on_realize ();
958 Editor::start_scrolling ()
960 scroll_connection = ARDOUR_UI::instance()->SuperRapidScreenUpdate.connect
961 (mem_fun(*this, &Editor::update_current_screen));
965 Editor::stop_scrolling ()
967 scroll_connection.disconnect ();
971 Editor::map_position_change (nframes_t frame)
973 ENSURE_GUI_THREAD (bind (mem_fun(*this, &Editor::map_position_change), frame));
975 if (session == 0 || !_follow_playhead) {
979 center_screen (frame);
980 playhead_cursor->set_position (frame);
984 Editor::center_screen (nframes_t frame)
986 double page = canvas_width * frames_per_unit;
988 /* if we're off the page, then scroll.
991 if (frame < leftmost_frame || frame >= leftmost_frame + page) {
992 center_screen_internal (frame, page);
997 Editor::center_screen_internal (nframes_t frame, float page)
1002 frame -= (nframes_t) page;
1007 reset_x_origin (frame);
1011 Editor::handle_new_duration ()
1013 ENSURE_GUI_THREAD (mem_fun (*this, &Editor::handle_new_duration));
1015 nframes_t new_end = session->get_maximum_extent() + (nframes_t) floorf (current_page_frames() * 0.10f);
1017 if (new_end > last_canvas_frame) {
1018 last_canvas_frame = new_end;
1019 horizontal_adjustment.set_upper (last_canvas_frame / frames_per_unit);
1020 reset_scrolling_region ();
1023 horizontal_adjustment.set_value (leftmost_frame/frames_per_unit);
1027 Editor::update_title_s (const string & snap_name)
1029 ENSURE_GUI_THREAD(bind (mem_fun(*this, &Editor::update_title_s), snap_name));
1035 Editor::update_title ()
1037 ENSURE_GUI_THREAD (mem_fun(*this, &Editor::update_title));
1040 bool dirty = session->dirty();
1042 string session_name;
1044 if (session->snap_name() != session->name()) {
1045 session_name = session->snap_name();
1047 session_name = session->name();
1051 session_name = "*" + session_name;
1054 WindowTitle title(session_name);
1055 title += Glib::get_application_name();
1056 set_title (title.get_string());
1061 Editor::connect_to_session (Session *t)
1065 XMLNode* node = ARDOUR_UI::instance()->editor_settings();
1068 /* catch up with the playhead */
1070 session->request_locate (playhead_cursor->current_frame);
1072 if (first_action_message) {
1073 first_action_message->hide();
1078 session->GoingAway.connect (mem_fun(*this, &Editor::session_going_away));
1079 session->history().Changed.connect (mem_fun (*this, &Editor::history_changed));
1081 /* These signals can all be emitted by a non-GUI thread. Therefore the
1082 handlers for them must not attempt to directly interact with the GUI,
1083 but use Gtkmm2ext::UI::instance()->call_slot();
1086 session_connections.push_back (session->TransportStateChange.connect (mem_fun(*this, &Editor::map_transport_state)));
1087 session_connections.push_back (session->PositionChanged.connect (mem_fun(*this, &Editor::map_position_change)));
1088 session_connections.push_back (session->RouteAdded.connect (mem_fun(*this, &Editor::handle_new_route)));
1089 session_connections.push_back (session->RegionAdded.connect (mem_fun(*this, &Editor::handle_new_region)));
1090 session_connections.push_back (session->RegionRemoved.connect (mem_fun(*this, &Editor::handle_region_removed)));
1091 session_connections.push_back (session->DurationChanged.connect (mem_fun(*this, &Editor::handle_new_duration)));
1092 session_connections.push_back (session->edit_group_added.connect (mem_fun(*this, &Editor::add_edit_group)));
1093 session_connections.push_back (session->edit_group_removed.connect (mem_fun(*this, &Editor::edit_groups_changed)));
1094 session_connections.push_back (session->NamedSelectionAdded.connect (mem_fun(*this, &Editor::handle_new_named_selection)));
1095 session_connections.push_back (session->NamedSelectionRemoved.connect (mem_fun(*this, &Editor::handle_new_named_selection)));
1096 session_connections.push_back (session->DirtyChanged.connect (mem_fun(*this, &Editor::update_title)));
1097 session_connections.push_back (session->StateSaved.connect (mem_fun(*this, &Editor::update_title_s)));
1098 session_connections.push_back (session->AskAboutPlaylistDeletion.connect (mem_fun(*this, &Editor::playlist_deletion_dialog)));
1099 session_connections.push_back (session->RegionHiddenChange.connect (mem_fun(*this, &Editor::region_hidden)));
1101 session_connections.push_back (session->SMPTEOffsetChanged.connect (mem_fun(*this, &Editor::update_just_smpte)));
1103 session_connections.push_back (session->tempo_map().StateChanged.connect (mem_fun(*this, &Editor::tempo_map_changed)));
1105 edit_groups_changed ();
1107 edit_cursor_clock.set_session (session);
1108 zoom_range_clock.set_session (session);
1109 _playlist_selector->set_session (session);
1110 nudge_clock.set_session (session);
1113 if (analysis_window != 0)
1114 analysis_window->set_session (session);
1117 Location* loc = session->locations()->auto_loop_location();
1119 loc = new Location (0, session->current_end_frame(), _("Loop"),(Location::Flags) (Location::IsAutoLoop | Location::IsHidden));
1120 if (loc->start() == loc->end()) {
1121 loc->set_end (loc->start() + 1);
1123 session->locations()->add (loc, false);
1124 session->set_auto_loop_location (loc);
1127 loc->set_name (_("Loop"));
1130 loc = session->locations()->auto_punch_location();
1132 loc = new Location (0, session->current_end_frame(), _("Punch"), (Location::Flags) (Location::IsAutoPunch | Location::IsHidden));
1133 if (loc->start() == loc->end()) {
1134 loc->set_end (loc->start() + 1);
1136 session->locations()->add (loc, false);
1137 session->set_auto_punch_location (loc);
1140 loc->set_name (_("Punch"));
1143 Config->map_parameters (mem_fun (*this, &Editor::parameter_changed));
1145 session->StateSaved.connect (mem_fun(*this, &Editor::session_state_saved));
1147 refresh_location_display ();
1148 session->locations()->added.connect (mem_fun(*this, &Editor::add_new_location));
1149 session->locations()->removed.connect (mem_fun(*this, &Editor::location_gone));
1150 session->locations()->changed.connect (mem_fun(*this, &Editor::refresh_location_display));
1151 session->locations()->StateChanged.connect (mem_fun(*this, &Editor::refresh_location_display_s));
1152 session->locations()->end_location()->changed.connect (mem_fun(*this, &Editor::end_location_changed));
1154 handle_new_duration ();
1156 redisplay_regions ();
1157 redisplay_named_selections ();
1158 redisplay_snapshots ();
1160 initial_route_list_display ();
1162 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
1163 (static_cast<TimeAxisView*>(*i))->set_samples_per_unit (frames_per_unit);
1166 restore_ruler_visibility ();
1167 //tempo_map_changed (Change (0));
1168 session->tempo_map().apply_with_metrics (*this, &Editor::draw_metric_marks);
1172 /* don't show master bus in a new session */
1174 if (ARDOUR_UI::instance()->session_is_new ()) {
1176 TreeModel::Children rows = route_display_model->children();
1177 TreeModel::Children::iterator i;
1179 no_route_list_redisplay = true;
1181 for (i = rows.begin(); i != rows.end(); ++i) {
1182 TimeAxisView *tv = (*i)[route_display_columns.tv];
1183 RouteTimeAxisView *rtv;
1185 if ((rtv = dynamic_cast<RouteTimeAxisView*>(tv)) != 0) {
1186 if (rtv->route()->is_master()) {
1187 route_list_display.get_selection()->unselect (i);
1192 no_route_list_redisplay = false;
1193 redisplay_route_list ();
1196 /* register for undo history */
1198 session->register_with_memento_command_factory(_id, this);
1202 Editor::build_cursors ()
1204 using namespace Gdk;
1206 Gdk::Color mbg ("#000000" ); /* Black */
1207 Gdk::Color mfg ("#0000ff" ); /* Blue. */
1210 RefPtr<Bitmap> source, mask;
1211 source = Bitmap::create (mag_bits, mag_width, mag_height);
1212 mask = Bitmap::create (magmask_bits, mag_width, mag_height);
1213 zoom_cursor = new Gdk::Cursor (source, mask, mfg, mbg, mag_x_hot, mag_y_hot);
1216 Gdk::Color fbg ("#ffffff" );
1217 Gdk::Color ffg ("#000000" );
1220 RefPtr<Bitmap> source, mask;
1222 source = Bitmap::create (fader_cursor_bits, fader_cursor_width, fader_cursor_height);
1223 mask = Bitmap::create (fader_cursor_mask_bits, fader_cursor_width, fader_cursor_height);
1224 fader_cursor = new Gdk::Cursor (source, mask, ffg, fbg, fader_cursor_x_hot, fader_cursor_y_hot);
1228 RefPtr<Bitmap> source, mask;
1229 source = Bitmap::create (speaker_cursor_bits, speaker_cursor_width, speaker_cursor_height);
1230 mask = Bitmap::create (speaker_cursor_mask_bits, speaker_cursor_width, speaker_cursor_height);
1231 speaker_cursor = new Gdk::Cursor (source, mask, ffg, fbg, speaker_cursor_x_hot, speaker_cursor_y_hot);
1234 grabber_cursor = new Gdk::Cursor (HAND2);
1235 cross_hair_cursor = new Gdk::Cursor (CROSSHAIR);
1236 trimmer_cursor = new Gdk::Cursor (SB_H_DOUBLE_ARROW);
1237 selector_cursor = new Gdk::Cursor (XTERM);
1238 time_fx_cursor = new Gdk::Cursor (SIZING);
1239 wait_cursor = new Gdk::Cursor (WATCH);
1240 timebar_cursor = new Gdk::Cursor(LEFT_PTR);
1241 midi_select_cursor = new Gdk::Cursor (CENTER_PTR);
1242 midi_pencil_cursor = new Gdk::Cursor (PENCIL);
1243 midi_erase_cursor = new Gdk::Cursor (DRAPED_BOX);
1246 /** Pop up a context menu for when the user clicks on a fade in or fade out */
1248 Editor::popup_fade_context_menu (int button, int32_t time, ArdourCanvas::Item* item, ItemType item_type)
1250 using namespace Menu_Helpers;
1251 AudioRegionView* arv = static_cast<AudioRegionView*> (item->get_data ("regionview"));
1254 fatal << _("programming error: fade in canvas item has no regionview data pointer!") << endmsg;
1258 MenuList& items (fade_context_menu.items());
1262 switch (item_type) {
1264 case FadeInHandleItem:
1265 if (arv->audio_region()->fade_in_active()) {
1266 items.push_back (MenuElem (_("Deactivate"), bind (mem_fun (*this, &Editor::set_fade_in_active), false)));
1268 items.push_back (MenuElem (_("Activate"), bind (mem_fun (*this, &Editor::set_fade_in_active), true)));
1271 items.push_back (SeparatorElem());
1273 items.push_back (MenuElem (_("Linear"), bind (mem_fun (*this, &Editor::set_fade_in_shape), AudioRegion::Linear)));
1274 items.push_back (MenuElem (_("Slowest"), bind (mem_fun (*this, &Editor::set_fade_in_shape), AudioRegion::Fast)));
1275 items.push_back (MenuElem (_("Slow"), bind (mem_fun (*this, &Editor::set_fade_in_shape), AudioRegion::LogB)));
1276 items.push_back (MenuElem (_("Fast"), bind (mem_fun (*this, &Editor::set_fade_in_shape), AudioRegion::LogA)));
1277 items.push_back (MenuElem (_("Fastest"), bind (mem_fun (*this, &Editor::set_fade_in_shape), AudioRegion::Slow)));
1281 case FadeOutHandleItem:
1282 if (arv->audio_region()->fade_out_active()) {
1283 items.push_back (MenuElem (_("Deactivate"), bind (mem_fun (*this, &Editor::set_fade_out_active), false)));
1285 items.push_back (MenuElem (_("Activate"), bind (mem_fun (*this, &Editor::set_fade_out_active), true)));
1288 items.push_back (SeparatorElem());
1290 items.push_back (MenuElem (_("Linear"), bind (mem_fun (*this, &Editor::set_fade_out_shape), AudioRegion::Linear)));
1291 items.push_back (MenuElem (_("Slowest"), bind (mem_fun (*this, &Editor::set_fade_out_shape), AudioRegion::Slow)));
1292 items.push_back (MenuElem (_("Slow"), bind (mem_fun (*this, &Editor::set_fade_out_shape), AudioRegion::LogA)));
1293 items.push_back (MenuElem (_("Fast"), bind (mem_fun (*this, &Editor::set_fade_out_shape), AudioRegion::LogB)));
1294 items.push_back (MenuElem (_("Fastest"), bind (mem_fun (*this, &Editor::set_fade_out_shape), AudioRegion::Fast)));
1299 fatal << _("programming error: ")
1300 << X_("non-fade canvas item passed to popup_fade_context_menu()")
1305 fade_context_menu.popup (button, time);
1308 /* Pop up the general track context menu for when the user clicks pretty much anywhere in a track or bus */
1310 Editor::popup_track_context_menu (int button, int32_t time, nframes_t frame)
1312 build_track_context_menu (frame)->popup (button, time);
1316 Editor::build_track_context_menu (nframes_t frame)
1318 using namespace Menu_Helpers;
1320 Menu* menu = manage (new Menu);
1321 MenuList& edit_items = menu->items();
1324 /* Build the general `track' context menu, adding what is appropriate given
1325 the current selection */
1327 /* XXX: currently crossfades can't be selected, so we can't use the selection
1328 to decide which crossfades to mention in the menu. I believe this will
1329 change at some point. For now we have to use clicked_trackview to decide. */
1330 AudioTimeAxisView* atv = dynamic_cast<AudioTimeAxisView*> (clicked_axisview);
1333 boost::shared_ptr<Diskstream> ds;
1334 boost::shared_ptr<Playlist> pl;
1335 boost::shared_ptr<AudioPlaylist> apl;
1337 if ((ds = atv->get_diskstream()) && ((pl = ds->playlist()) != 0) && ((apl = boost::dynamic_pointer_cast<AudioPlaylist> (pl)) != 0)) {
1339 AudioPlaylist::Crossfades xfades;
1340 apl->crossfades_at (frame, xfades);
1342 bool many = xfades.size() > 1;
1344 for (AudioPlaylist::Crossfades::iterator i = xfades.begin(); i != xfades.end(); ++i) {
1345 add_crossfade_context_items (atv->audio_view(), (*i), edit_items, many);
1350 if (!selection->time.empty()) {
1351 add_selection_context_items (edit_items);
1354 if (!selection->regions.empty()) {
1355 add_region_context_items (edit_items);
1358 if (!selection->tracks.empty()) {
1359 add_bus_or_audio_track_context_items (edit_items);
1362 menu->set_name ("ArdourContextMenu");
1369 Editor::analyze_region_selection()
1371 if (analysis_window == 0) {
1372 analysis_window = new AnalysisWindow();
1375 analysis_window->set_session(session);
1377 analysis_window->show_all();
1380 analysis_window->set_regionmode();
1381 analysis_window->analyze();
1383 analysis_window->present();
1387 Editor::analyze_range_selection()
1389 if (analysis_window == 0) {
1390 analysis_window = new AnalysisWindow();
1393 analysis_window->set_session(session);
1395 analysis_window->show_all();
1398 analysis_window->set_rangemode();
1399 analysis_window->analyze();
1401 analysis_window->present();
1403 #endif /* FFT_ANALYSIS */
1406 /** Add context menu items relevant to crossfades.
1407 * @param edit_items List to add the items to.
1410 Editor::add_crossfade_context_items (AudioStreamView* view, boost::shared_ptr<Crossfade> xfade, Menu_Helpers::MenuList& edit_items, bool many)
1412 using namespace Menu_Helpers;
1413 Menu *xfade_menu = manage (new Menu);
1414 MenuList& items = xfade_menu->items();
1415 xfade_menu->set_name ("ArdourContextMenu");
1418 if (xfade->active()) {
1424 items.push_back (MenuElem (str, bind (mem_fun(*this, &Editor::toggle_xfade_active), boost::weak_ptr<Crossfade> (xfade))));
1425 items.push_back (MenuElem (_("Edit"), bind (mem_fun(*this, &Editor::edit_xfade), boost::weak_ptr<Crossfade> (xfade))));
1427 if (xfade->can_follow_overlap()) {
1429 if (xfade->following_overlap()) {
1430 str = _("Convert to short");
1432 str = _("Convert to full");
1435 items.push_back (MenuElem (str, bind (mem_fun(*this, &Editor::toggle_xfade_length), xfade)));
1439 str = xfade->out()->name();
1441 str += xfade->in()->name();
1443 str = _("Crossfade");
1446 edit_items.push_back (MenuElem (str, *xfade_menu));
1447 edit_items.push_back (SeparatorElem());
1451 Editor::xfade_edit_left_region ()
1453 if (clicked_crossfadeview) {
1454 clicked_crossfadeview->left_view.show_region_editor ();
1459 Editor::xfade_edit_right_region ()
1461 if (clicked_crossfadeview) {
1462 clicked_crossfadeview->right_view.show_region_editor ();
1466 /** Add an element to a menu, settings its sensitivity.
1467 * @param m Menu to add to.
1468 * @param e Element to add.
1469 * @param s true to make sensitive, false to make insensitive
1472 Editor::add_item_with_sensitivity (Menu_Helpers::MenuList& m, Menu_Helpers::MenuElem e, bool s) const
1476 m.back().set_sensitive (false);
1480 /** Add context menu items relevant to regions.
1481 * @param edit_items List to add the items to.
1484 Editor::add_region_context_items (Menu_Helpers::MenuList& edit_items)
1486 using namespace Menu_Helpers;
1487 Menu *region_menu = manage (new Menu);
1488 MenuList& items = region_menu->items();
1489 region_menu->set_name ("ArdourContextMenu");
1491 items.push_back (MenuElem (_("Edit..."), mem_fun(*this, &Editor::edit_region)));
1492 items.push_back (MenuElem (_("Raise to top layer"), mem_fun(*this, &Editor::raise_region_to_top)));
1493 items.push_back (MenuElem (_("Lower to bottom layer"), mem_fun (*this, &Editor::lower_region_to_bottom)));
1495 Menu* sync_point_menu = manage (new Menu);
1496 MenuList& sync_point_items = sync_point_menu->items();
1497 sync_point_menu->set_name("ArdourContextMenu");
1499 sync_point_items.push_back (MenuElem (_("Define"), mem_fun(*this, &Editor::set_region_sync_from_edit_cursor)));
1500 sync_point_items.push_back (MenuElem (_("Remove"), mem_fun(*this, &Editor::remove_region_sync)));
1502 items.push_back (MenuElem (_("Sync points"), *sync_point_menu));
1504 add_item_with_sensitivity (items, MenuElem (_("Audition"), mem_fun(*this, &Editor::audition_selected_region)), selection->regions.size() == 1);
1506 add_item_with_sensitivity (items, MenuElem (_("Export"), mem_fun(*this, &Editor::export_region)), selection->regions.size() == 1);
1508 items.push_back (MenuElem (_("Bounce"), mem_fun(*this, &Editor::bounce_region_selection)));
1511 items.push_back (MenuElem (_("Analyze region"), mem_fun(*this, &Editor::analyze_region_selection)));
1514 items.push_back (SeparatorElem());
1516 items.push_back (MenuElem (_("Lock"), bind (mem_fun (*this, &Editor::set_region_lock), true)));
1517 items.push_back (MenuElem (_("Unlock"), bind (mem_fun (*this, &Editor::set_region_lock), false)));
1518 items.push_back (MenuElem (_("Lock Position"), bind (mem_fun (*this, &Editor::set_region_position_lock), true)));
1519 items.push_back (MenuElem (_("Unlock Position"), bind (mem_fun (*this, &Editor::set_region_position_lock), false)));
1520 items.push_back (MenuElem (_("Mute"), bind (mem_fun (*this, &Editor::set_region_mute), true)));
1521 items.push_back (MenuElem (_("Unmute"), bind (mem_fun (*this, &Editor::set_region_mute), false)));
1522 items.push_back (MenuElem (_("Opaque"), bind (mem_fun (*this, &Editor::set_region_opaque), true)));
1523 items.push_back (MenuElem (_("Transparent"), bind (mem_fun (*this, &Editor::set_region_opaque), false)));
1525 /* We allow "Original position" if at least one region is not at its
1528 RegionSelection::iterator i = selection->regions.begin();
1529 while (i != selection->regions.end() && (*i)->region()->at_natural_position() == true) {
1533 add_item_with_sensitivity (items, MenuElem (_("Original position"), mem_fun(*this, &Editor::naturalize)), i != selection->regions.end());
1535 items.push_back (SeparatorElem());
1537 /* Find out if we have a selected audio region */
1538 i = selection->regions.begin();
1539 while (i != selection->regions.end() && boost::dynamic_pointer_cast<AudioRegion>((*i)->region()) == 0) {
1542 const bool have_selected_audio_region = (i != selection->regions.end());
1544 if (have_selected_audio_region) {
1546 Menu* envelopes_menu = manage (new Menu);
1547 MenuList& envelopes_items = envelopes_menu->items();
1548 envelopes_menu->set_name ("ArdourContextMenu");
1550 envelopes_items.push_back (MenuElem (_("Reset"), mem_fun(*this, &Editor::reset_region_gain_envelopes)));
1551 envelopes_items.push_back (MenuElem (_("Visible"), bind (mem_fun (*this, &Editor::set_gain_envelope_visibility), true)));
1552 envelopes_items.push_back (MenuElem (_("Invisible"), bind (mem_fun (*this, &Editor::set_gain_envelope_visibility), false)));
1553 envelopes_items.push_back (MenuElem (_("Active"), bind (mem_fun (*this, &Editor::set_gain_envelope_active), true)));
1554 envelopes_items.push_back (MenuElem (_("Inactive"), bind (mem_fun (*this, &Editor::set_gain_envelope_active), false)));
1556 items.push_back (MenuElem (_("Envelopes"), *envelopes_menu));
1558 items.push_back (MenuElem (_("Denormalize"), mem_fun (*this, &Editor::denormalize_regions)));
1559 items.push_back (MenuElem (_("Normalize"), mem_fun (*this, &Editor::normalize_regions)));
1562 /* Find out if we have a selected MIDI region */
1563 i = selection->regions.begin();
1564 while (i != selection->regions.end() && boost::dynamic_pointer_cast<MidiRegion>((*i)->region()) == 0) {
1567 const bool have_selected_midi_region = (i != selection->regions.end());
1569 if (have_selected_midi_region) {
1571 items.push_back (MenuElem (_("Quantize"), mem_fun(*this, &Editor::quantize_regions)));
1572 items.push_back (SeparatorElem());
1576 /* range related stuff */
1578 add_item_with_sensitivity (items, MenuElem (_("Add range markers"), mem_fun (*this, &Editor::add_location_from_audio_region)), selection->regions.size() == 1);
1580 add_item_with_sensitivity (items, MenuElem (_("Set range selection"), mem_fun (*this, &Editor::set_selection_from_audio_region)), selection->regions.size() == 1);
1582 items.push_back (SeparatorElem());
1586 Menu *nudge_menu = manage (new Menu());
1587 MenuList& nudge_items = nudge_menu->items();
1588 nudge_menu->set_name ("ArdourContextMenu");
1590 nudge_items.push_back (MenuElem (_("Nudge forward"), (bind (mem_fun(*this, &Editor::nudge_forward), false))));
1591 nudge_items.push_back (MenuElem (_("Nudge backward"), (bind (mem_fun(*this, &Editor::nudge_backward), false))));
1592 nudge_items.push_back (MenuElem (_("Nudge forward by capture offset"), (mem_fun(*this, &Editor::nudge_forward_capture_offset))));
1593 nudge_items.push_back (MenuElem (_("Nudge backward by capture offset"), (mem_fun(*this, &Editor::nudge_backward_capture_offset))));
1595 items.push_back (MenuElem (_("Nudge"), *nudge_menu));
1597 Menu *trim_menu = manage (new Menu);
1598 MenuList& trim_items = trim_menu->items();
1599 trim_menu->set_name ("ArdourContextMenu");
1601 trim_items.push_back (MenuElem (_("Start to edit cursor"), mem_fun(*this, &Editor::trim_region_from_edit_cursor)));
1602 trim_items.push_back (MenuElem (_("Edit cursor to end"), mem_fun(*this, &Editor::trim_region_to_edit_cursor)));
1604 items.push_back (MenuElem (_("Trim"), *trim_menu));
1605 items.push_back (MenuElem (_("Split"), (mem_fun(*this, &Editor::split_region))));
1606 items.push_back (MenuElem (_("Make mono regions"), (mem_fun(*this, &Editor::split_multichannel_region))));
1607 items.push_back (MenuElem (_("Duplicate"), (bind (mem_fun(*this, &Editor::duplicate_dialog), true))));
1608 items.push_back (MenuElem (_("Fill track"), (mem_fun(*this, &Editor::region_fill_track))));
1609 items.push_back (SeparatorElem());
1610 items.push_back (MenuElem (_("Remove"), mem_fun(*this, &Editor::remove_selected_regions)));
1612 /* OK, stick the region submenu at the top of the list, and then add
1616 string const menu_item_name = selection->regions.size() > 1 ? _("Regions") : _("Region");
1617 edit_items.push_back (MenuElem (menu_item_name, *region_menu));
1620 /** Add context menu items relevant to selection ranges.
1621 * @param edit_items List to add the items to.
1624 Editor::add_selection_context_items (Menu_Helpers::MenuList& edit_items)
1626 using namespace Menu_Helpers;
1627 Menu *selection_menu = manage (new Menu);
1628 MenuList& items = selection_menu->items();
1629 selection_menu->set_name ("ArdourContextMenu");
1631 items.push_back (MenuElem (_("Play range"), mem_fun(*this, &Editor::play_selection)));
1632 items.push_back (MenuElem (_("Loop range"), mem_fun(*this, &Editor::set_route_loop_selection)));
1635 items.push_back (SeparatorElem());
1636 items.push_back (MenuElem (_("Analyze range"), mem_fun(*this, &Editor::analyze_range_selection)));
1639 items.push_back (SeparatorElem());
1640 items.push_back (MenuElem (_("Separate range to track"), mem_fun(*this, &Editor::separate_region_from_selection)));
1641 items.push_back (MenuElem (_("Separate range to region list"), mem_fun(*this, &Editor::new_region_from_selection)));
1643 items.push_back (SeparatorElem());
1644 items.push_back (MenuElem (_("Select all in range"), mem_fun(*this, &Editor::select_all_selectables_using_time_selection)));
1645 items.push_back (SeparatorElem());
1646 items.push_back (MenuElem (_("Add range markers"), mem_fun (*this, &Editor::add_location_from_selection)));
1647 items.push_back (MenuElem (_("Set range to loop range"), mem_fun(*this, &Editor::set_selection_from_loop)));
1648 items.push_back (MenuElem (_("Set range to punch range"), mem_fun(*this, &Editor::set_selection_from_punch)));
1649 items.push_back (SeparatorElem());
1650 items.push_back (MenuElem (_("Crop region to range"), mem_fun(*this, &Editor::crop_region_to_selection)));
1651 items.push_back (MenuElem (_("Fill range with region"), mem_fun(*this, &Editor::region_fill_selection)));
1652 items.push_back (MenuElem (_("Duplicate range"), bind (mem_fun(*this, &Editor::duplicate_dialog), false)));
1653 items.push_back (MenuElem (_("Create chunk from range"), mem_fun(*this, &Editor::create_named_selection)));
1654 items.push_back (SeparatorElem());
1655 items.push_back (MenuElem (_("Bounce range"), mem_fun(*this, &Editor::bounce_range_selection)));
1656 items.push_back (MenuElem (_("Export range"), mem_fun(*this, &Editor::export_selection)));
1658 edit_items.push_back (MenuElem (_("Range"), *selection_menu));
1659 edit_items.push_back (SeparatorElem());
1662 /** Add context menu items relevant to busses or audio tracks.
1663 * @param edit_items List to add the items to.
1666 Editor::add_bus_or_audio_track_context_items (Menu_Helpers::MenuList& edit_items)
1668 using namespace Menu_Helpers;
1670 /* We add every possible action here, and de-sensitize things
1671 that aren't allowed. The sensitivity logic is a bit spread out;
1672 on the one hand I'm using things like can_cut_copy (), which is
1673 reasonably complicated and so perhaps better near the function that
1674 it expresses sensitivity for, and on the other hand checks
1675 in this function as well. You can't really have can_* for everything
1676 or the number of methods would get silly. */
1678 bool const one_selected_region = selection->regions.size() == 1;
1680 /* Count the number of selected audio tracks */
1681 int n_audio_tracks = 0;
1682 for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
1683 RouteTimeAxisView const * r = dynamic_cast<RouteTimeAxisView*>(*i);
1684 if (r && r->is_audio_track()) {
1691 Menu *play_menu = manage (new Menu);
1692 MenuList& play_items = play_menu->items();
1693 play_menu->set_name ("ArdourContextMenu");
1695 play_items.push_back (MenuElem (_("Play from edit cursor"), mem_fun(*this, &Editor::play_from_edit_cursor)));
1696 play_items.push_back (MenuElem (_("Play from start"), mem_fun(*this, &Editor::play_from_start)));
1697 add_item_with_sensitivity (play_items, MenuElem (_("Play region"), mem_fun(*this, &Editor::play_selected_region)), one_selected_region);
1699 add_item_with_sensitivity (play_items, MenuElem (_("Loop region"), mem_fun(*this, &Editor::loop_selected_region)), one_selected_region);
1701 edit_items.push_back (MenuElem (_("Play"), *play_menu));
1705 Menu *select_menu = manage (new Menu);
1706 MenuList& select_items = select_menu->items();
1707 select_menu->set_name ("ArdourContextMenu");
1709 string str = selection->tracks.size() == 1 ? _("Select all in track") : _("Select all in tracks");
1711 select_items.push_back (MenuElem (str, bind (mem_fun(*this, &Editor::select_all_in_selected_tracks), Selection::Set)));
1713 select_items.push_back (MenuElem (_("Select all"), bind (mem_fun(*this, &Editor::select_all), Selection::Set)));
1715 str = selection->tracks.size() == 1 ? _("Invert selection in track") : _("Invert selection in tracks");
1717 select_items.push_back (MenuElem (str, mem_fun(*this, &Editor::invert_selection_in_selected_tracks)));
1719 select_items.push_back (MenuElem (_("Invert selection"), mem_fun(*this, &Editor::invert_selection)));
1720 select_items.push_back (SeparatorElem());
1722 if (n_audio_tracks) {
1723 select_items.push_back (MenuElem (_("Set range to loop range"), mem_fun(*this, &Editor::set_selection_from_loop)));
1724 select_items.push_back (MenuElem (_("Set range to punch range"), mem_fun(*this, &Editor::set_selection_from_punch)));
1727 select_items.push_back (MenuElem (_("Select all after edit cursor"), bind (mem_fun(*this, &Editor::select_all_selectables_using_cursor), edit_cursor, true)));
1728 select_items.push_back (MenuElem (_("Select all before edit cursor"), bind (mem_fun(*this, &Editor::select_all_selectables_using_cursor), edit_cursor, false)));
1729 select_items.push_back (MenuElem (_("Select all after playhead"), bind (mem_fun(*this, &Editor::select_all_selectables_using_cursor), playhead_cursor, true)));
1730 select_items.push_back (MenuElem (_("Select all before playhead"), bind (mem_fun(*this, &Editor::select_all_selectables_using_cursor), playhead_cursor, false)));
1732 if (n_audio_tracks) {
1733 select_items.push_back (MenuElem (_("Select all between cursors"), bind (mem_fun(*this, &Editor::select_all_selectables_between_cursors), playhead_cursor, edit_cursor)));
1736 edit_items.push_back (MenuElem (_("Select"), *select_menu));
1740 Menu *cutnpaste_menu = manage (new Menu);
1741 MenuList& cutnpaste_items = cutnpaste_menu->items();
1742 cutnpaste_menu->set_name ("ArdourContextMenu");
1744 add_item_with_sensitivity (cutnpaste_items, MenuElem (_("Cut"), mem_fun(*this, &Editor::cut)), can_cut_copy ());
1746 add_item_with_sensitivity (cutnpaste_items, MenuElem (_("Copy"), mem_fun(*this, &Editor::copy)), can_cut_copy ());
1748 if (n_audio_tracks) {
1749 cutnpaste_items.push_back (MenuElem (_("Paste at edit cursor"), bind (mem_fun(*this, &Editor::paste), 1.0f)));
1750 cutnpaste_items.push_back (MenuElem (_("Paste at mouse"), mem_fun(*this, &Editor::mouse_paste)));
1752 cutnpaste_items.push_back (SeparatorElem());
1754 cutnpaste_items.push_back (MenuElem (_("Align"), bind (mem_fun(*this, &Editor::align), ARDOUR::SyncPoint)));
1755 cutnpaste_items.push_back (MenuElem (_("Align relative"), bind (mem_fun(*this, &Editor::align_relative), ARDOUR::SyncPoint)));
1756 cutnpaste_items.push_back (MenuElem (_("Insert chunk"), bind (mem_fun(*this, &Editor::paste_named_selection), 1.0f)));
1758 cutnpaste_items.push_back (MenuElem (_("Paste"), bind (mem_fun(*this, &Editor::paste), 1.0f)));
1761 edit_items.push_back (MenuElem (_("Edit"), *cutnpaste_menu));
1763 if (n_audio_tracks) {
1765 Menu *track_menu = manage (new Menu);
1766 MenuList& track_items = track_menu->items();
1767 track_menu->set_name ("ArdourContextMenu");
1769 /* Adding new material */
1771 add_item_with_sensitivity (track_items, MenuElem (_("Insert selected region"), bind (mem_fun(*this, &Editor::insert_region_list_selection), 1.0f)), n_audio_tracks == 1);
1773 add_item_with_sensitivity (track_items, MenuElem (_("Insert existing audio"), bind (mem_fun(*this, &Editor::add_external_audio_action), ImportToTrack)), n_audio_tracks == 1);
1777 Menu *nudge_menu = manage (new Menu());
1778 MenuList& nudge_items = nudge_menu->items();
1779 nudge_menu->set_name ("ArdourContextMenu");
1781 str = selection->tracks.size() == 1 ? _("Nudge track forward") : _("Nude tracks forward");
1782 nudge_items.push_back (MenuElem (str, (bind (mem_fun(*this, &Editor::nudge_selected_tracks), false, true))));
1784 str = selection->tracks.size() == 1 ? _("Nudge track after edit cursor forward") : _("Nudge tracks after edit cursor forward");
1786 nudge_items.push_back (MenuElem (str, (bind (mem_fun(*this, &Editor::nudge_selected_tracks), true, true))));
1788 str = selection->tracks.size() == 1 ? _("Nudge track backward") : _("Nudge tracks backward");
1790 nudge_items.push_back (MenuElem (str, (bind (mem_fun(*this, &Editor::nudge_selected_tracks), false, false))));
1792 str = selection->tracks.size() == 1 ? _("Nudge track after edit cursor backward") : _("Nudge tracks after edit cursor backward");
1794 nudge_items.push_back (MenuElem (str, (bind (mem_fun(*this, &Editor::nudge_selected_tracks), true, false))));
1796 track_items.push_back (MenuElem (_("Nudge"), *nudge_menu));
1799 track_items.push_back (MenuElem (_("Freeze"), mem_fun(*this, &Editor::freeze_routes)));
1800 track_items.push_back (MenuElem (_("Unfreeze"), mem_fun(*this, &Editor::unfreeze_routes)));
1802 str = selection->tracks.size() == 1 ? _("Track") : _("Tracks");
1803 edit_items.push_back (MenuElem (str, *track_menu));
1807 /* CURSOR SETTING AND MARKS AND STUFF */
1810 Editor::set_snap_to (SnapType st)
1813 string str = snap_type_strings[(int) st];
1815 if (str != snap_type_selector.get_active_text()) {
1816 snap_type_selector.set_active_text (str);
1821 switch (snap_type) {
1822 case SnapToAThirtysecondBeat:
1823 case SnapToASixteenthBeat:
1824 case SnapToAEighthBeat:
1825 case SnapToAQuarterBeat:
1826 case SnapToAThirdBeat:
1827 update_tempo_based_rulers ();
1835 Editor::set_snap_mode (SnapMode mode)
1838 string str = snap_mode_strings[(int)mode];
1840 if (str != snap_mode_selector.get_active_text ()) {
1841 snap_mode_selector.set_active_text (str);
1848 Editor::set_state (const XMLNode& node)
1850 const XMLProperty* prop;
1852 int x, y, xoff, yoff;
1855 if ((prop = node.property ("id")) != 0) {
1856 _id = prop->value ();
1859 if ((geometry = find_named_node (node, "geometry")) == 0) {
1861 g.base_width = default_width;
1862 g.base_height = default_height;
1870 g.base_width = atoi(geometry->property("x_size")->value());
1871 g.base_height = atoi(geometry->property("y_size")->value());
1872 x = atoi(geometry->property("x_pos")->value());
1873 y = atoi(geometry->property("y_pos")->value());
1874 xoff = atoi(geometry->property("x_off")->value());
1875 yoff = atoi(geometry->property("y_off")->value());
1878 set_default_size (g.base_width, g.base_height);
1881 if (session && (prop = node.property ("playhead"))) {
1882 nframes_t pos = atol (prop->value().c_str());
1883 playhead_cursor->set_position (pos);
1885 playhead_cursor->set_position (0);
1887 /* reset_x_origin() doesn't work right here, since the old
1888 position may be zero already, and it does nothing in such
1893 horizontal_adjustment.set_value (0);
1896 if (session && (prop = node.property ("edit-cursor"))) {
1897 nframes_t pos = atol (prop->value().c_str());
1898 edit_cursor->set_position (pos);
1900 edit_cursor->set_position (0);
1903 if ((prop = node.property ("mixer-width"))) {
1904 editor_mixer_strip_width = Width (string_2_enum (prop->value(), editor_mixer_strip_width));
1907 if ((prop = node.property ("zoom-focus"))) {
1908 set_zoom_focus ((ZoomFocus) atoi (prop->value()));
1911 if ((prop = node.property ("zoom"))) {
1912 reset_zoom (PBD::atof (prop->value()));
1915 if ((prop = node.property ("snap-to"))) {
1916 set_snap_to ((SnapType) atoi (prop->value()));
1919 if ((prop = node.property ("snap-mode"))) {
1920 set_snap_mode ((SnapMode) atoi (prop->value()));
1923 if ((prop = node.property ("mouse-mode"))) {
1924 MouseMode m = str2mousemode(prop->value());
1925 mouse_mode = MouseMode ((int) m + 1); /* lie, force mode switch */
1926 set_mouse_mode (m, true);
1928 mouse_mode = MouseGain; /* lie, to force the mode switch */
1929 set_mouse_mode (MouseObject, true);
1932 if ((prop = node.property ("show-waveforms"))) {
1933 bool yn = (prop->value() == "yes");
1934 _show_waveforms = !yn;
1935 RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("ToggleWaveformVisibility"));
1937 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
1938 /* do it twice to force the change */
1939 tact->set_active (!yn);
1940 tact->set_active (yn);
1944 if ((prop = node.property ("show-waveforms-recording"))) {
1945 bool yn = (prop->value() == "yes");
1946 _show_waveforms_recording = !yn;
1947 RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("ToggleWaveformsWhileRecording"));
1949 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
1950 /* do it twice to force the change */
1951 tact->set_active (!yn);
1952 tact->set_active (yn);
1956 if ((prop = node.property ("show-measures"))) {
1957 bool yn = (prop->value() == "yes");
1958 _show_measures = !yn;
1959 RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("ToggleMeasureVisibility"));
1961 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
1962 /* do it twice to force the change */
1963 tact->set_active (!yn);
1964 tact->set_active (yn);
1968 if ((prop = node.property ("follow-playhead"))) {
1969 bool yn = (prop->value() == "yes");
1970 set_follow_playhead (yn);
1971 RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("toggle-follow-playhead"));
1973 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
1974 if (tact->get_active() != yn) {
1975 tact->set_active (yn);
1980 if ((prop = node.property ("region-list-sort-type"))) {
1981 region_list_sort_type = (Editing::RegionListSortType) -1; // force change
1982 reset_region_list_sort_type(str2regionlistsorttype(prop->value()));
1985 if ((prop = node.property ("xfades-visible"))) {
1986 bool yn = (prop->value() == "yes");
1987 _xfade_visibility = !yn;
1988 // set_xfade_visibility (yn);
1991 if ((prop = node.property ("show-editor-mixer"))) {
1993 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("show-editor-mixer"));
1996 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
1997 bool yn = (prop->value() == X_("yes"));
1999 /* do it twice to force the change */
2001 tact->set_active (!yn);
2002 tact->set_active (yn);
2006 if ((prop = node.property ("show-editor-list"))) {
2008 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("show-editor-list"));
2012 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
2013 bool yn = (prop->value() == X_("yes"));
2015 /* do it twice to force the change */
2017 tact->set_active (!yn);
2018 tact->set_active (yn);
2027 Editor::get_state ()
2029 XMLNode* node = new XMLNode ("Editor");
2032 _id.print (buf, sizeof (buf));
2033 node->add_property ("id", buf);
2035 if (is_realized()) {
2036 Glib::RefPtr<Gdk::Window> win = get_window();
2038 int x, y, xoff, yoff, width, height;
2039 win->get_root_origin(x, y);
2040 win->get_position(xoff, yoff);
2041 win->get_size(width, height);
2043 XMLNode* geometry = new XMLNode ("geometry");
2045 snprintf(buf, sizeof(buf), "%d", width);
2046 geometry->add_property("x_size", string(buf));
2047 snprintf(buf, sizeof(buf), "%d", height);
2048 geometry->add_property("y_size", string(buf));
2049 snprintf(buf, sizeof(buf), "%d", x);
2050 geometry->add_property("x_pos", string(buf));
2051 snprintf(buf, sizeof(buf), "%d", y);
2052 geometry->add_property("y_pos", string(buf));
2053 snprintf(buf, sizeof(buf), "%d", xoff);
2054 geometry->add_property("x_off", string(buf));
2055 snprintf(buf, sizeof(buf), "%d", yoff);
2056 geometry->add_property("y_off", string(buf));
2057 snprintf(buf,sizeof(buf), "%d",gtk_paned_get_position (static_cast<Paned*>(&edit_pane)->gobj()));
2058 geometry->add_property("edit_pane_pos", string(buf));
2060 node->add_child_nocopy (*geometry);
2063 maybe_add_mixer_strip_width (*node);
2065 snprintf (buf, sizeof(buf), "%d", (int) zoom_focus);
2066 node->add_property ("zoom-focus", buf);
2067 snprintf (buf, sizeof(buf), "%f", frames_per_unit);
2068 node->add_property ("zoom", buf);
2069 snprintf (buf, sizeof(buf), "%d", (int) snap_type);
2070 node->add_property ("snap-to", buf);
2071 snprintf (buf, sizeof(buf), "%d", (int) snap_mode);
2072 node->add_property ("snap-mode", buf);
2074 snprintf (buf, sizeof (buf), "%" PRIu32, playhead_cursor->current_frame);
2075 node->add_property ("playhead", buf);
2076 snprintf (buf, sizeof (buf), "%" PRIu32, edit_cursor->current_frame);
2077 node->add_property ("edit-cursor", buf);
2079 node->add_property ("show-waveforms", _show_waveforms ? "yes" : "no");
2080 node->add_property ("show-waveforms-recording", _show_waveforms_recording ? "yes" : "no");
2081 node->add_property ("show-measures", _show_measures ? "yes" : "no");
2082 node->add_property ("follow-playhead", _follow_playhead ? "yes" : "no");
2083 node->add_property ("xfades-visible", _xfade_visibility ? "yes" : "no");
2084 node->add_property ("region-list-sort-type", enum2str(region_list_sort_type));
2085 node->add_property ("mouse-mode", enum2str(mouse_mode));
2087 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("show-editor-mixer"));
2089 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
2090 node->add_property (X_("show-editor-mixer"), tact->get_active() ? "yes" : "no");
2093 act = ActionManager::get_action (X_("Editor"), X_("show-editor-list"));
2095 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
2096 node->add_property (X_("show-editor-list"), tact->get_active() ? "yes" : "no");
2105 Editor::trackview_by_y_position (double y)
2107 for (TrackViewList::iterator iter = track_views.begin(); iter != track_views.end(); ++iter) {
2111 if ((tv = (*iter)->covers_y_position (y)) != 0) {
2120 Editor::snap_to (nframes64_t& start, int32_t direction, bool for_mark)
2122 Location* before = 0;
2123 Location* after = 0;
2129 const nframes64_t one_second = session->frame_rate();
2130 const nframes64_t one_minute = session->frame_rate() * 60;
2131 const nframes64_t one_smpte_second = (nframes64_t)(rint(session->smpte_frames_per_second()) * session->frames_per_smpte_frame());
2132 nframes64_t one_smpte_minute = (nframes64_t)(rint(session->smpte_frames_per_second()) * session->frames_per_smpte_frame() * 60);
2133 nframes64_t presnap = start;
2135 switch (snap_type) {
2141 start = (nframes_t) ceil ((double) start / (one_second / 75)) * (one_second / 75);
2143 start = (nframes_t) floor ((double) start / (one_second / 75)) * (one_second / 75);
2147 case SnapToSMPTEFrame:
2148 if (fmod((double)start, (double)session->frames_per_smpte_frame()) > (session->frames_per_smpte_frame() / 2)) {
2149 start = (nframes_t) (ceil ((double) start / session->frames_per_smpte_frame()) * session->frames_per_smpte_frame());
2151 start = (nframes_t) (floor ((double) start / session->frames_per_smpte_frame()) * session->frames_per_smpte_frame());
2155 case SnapToSMPTESeconds:
2156 if (session->smpte_offset_negative())
2158 start += session->smpte_offset ();
2160 start -= session->smpte_offset ();
2162 if (start % one_smpte_second > one_smpte_second / 2) {
2163 start = (nframes_t) ceil ((double) start / one_smpte_second) * one_smpte_second;
2165 start = (nframes_t) floor ((double) start / one_smpte_second) * one_smpte_second;
2168 if (session->smpte_offset_negative())
2170 start -= session->smpte_offset ();
2172 start += session->smpte_offset ();
2176 case SnapToSMPTEMinutes:
2177 if (session->smpte_offset_negative())
2179 start += session->smpte_offset ();
2181 start -= session->smpte_offset ();
2183 if (start % one_smpte_minute > one_smpte_minute / 2) {
2184 start = (nframes_t) ceil ((double) start / one_smpte_minute) * one_smpte_minute;
2186 start = (nframes_t) floor ((double) start / one_smpte_minute) * one_smpte_minute;
2188 if (session->smpte_offset_negative())
2190 start -= session->smpte_offset ();
2192 start += session->smpte_offset ();
2197 if (start % one_second > one_second / 2) {
2198 start = (nframes_t) ceil ((double) start / one_second) * one_second;
2200 start = (nframes_t) floor ((double) start / one_second) * one_second;
2205 if (start % one_minute > one_minute / 2) {
2206 start = (nframes_t) ceil ((double) start / one_minute) * one_minute;
2208 start = (nframes_t) floor ((double) start / one_minute) * one_minute;
2213 start = session->tempo_map().round_to_bar (start, direction);
2217 start = session->tempo_map().round_to_beat (start, direction);
2220 case SnapToAThirtysecondBeat:
2221 start = session->tempo_map().round_to_beat_subdivision (start, 32);
2224 case SnapToASixteenthBeat:
2225 start = session->tempo_map().round_to_beat_subdivision (start, 16);
2228 case SnapToAEighthBeat:
2229 start = session->tempo_map().round_to_beat_subdivision (start, 8);
2232 case SnapToAQuarterBeat:
2233 start = session->tempo_map().round_to_beat_subdivision (start, 4);
2236 case SnapToAThirdBeat:
2237 start = session->tempo_map().round_to_beat_subdivision (start, 3);
2240 case SnapToEditCursor:
2241 start = edit_cursor->current_frame;
2249 before = session->locations()->first_location_before (start);
2250 after = session->locations()->first_location_after (start);
2252 if (direction < 0) {
2254 start = before->start();
2258 } else if (direction > 0) {
2260 start = after->start();
2262 start = session->current_end_frame();
2267 /* find nearest of the two */
2268 if ((start - before->start()) < (after->start() - start)) {
2269 start = before->start();
2271 start = after->start();
2274 start = before->start();
2277 start = after->start();
2284 case SnapToRegionStart:
2285 case SnapToRegionEnd:
2286 case SnapToRegionSync:
2287 case SnapToRegionBoundary:
2288 if (!region_boundary_cache.empty()) {
2289 vector<nframes_t>::iterator i;
2291 if (direction > 0) {
2292 i = std::upper_bound (region_boundary_cache.begin(), region_boundary_cache.end(), start);
2294 i = std::lower_bound (region_boundary_cache.begin(), region_boundary_cache.end(), start);
2297 if (i != region_boundary_cache.end()) {
2300 start = region_boundary_cache.back();
2306 switch (snap_mode) {
2312 if (presnap > start) {
2313 if (presnap > (start + unit_to_frame(snap_threshold))) {
2317 } else if (presnap < start) {
2318 if (presnap < (start - unit_to_frame(snap_threshold))) {
2330 Editor::snap_length_beats (nframes_t start)
2336 /* FIXME: This could/should also work with non-tempo based snap settings (ie seconds) */
2338 switch (snap_type) {
2340 return session->tempo_map().meter_at(start).beats_per_bar();
2345 case SnapToAThirtysecondBeat:
2346 return 1.0 / (double)32.0;
2349 case SnapToASixteenthBeat:
2350 return 1.0 / (double)16.0;
2353 case SnapToAEighthBeat:
2354 return 1.0 / (double)8.0;
2357 case SnapToAQuarterBeat:
2358 return 1.0 / (double)4.0;
2361 case SnapToAThirdBeat:
2362 return 1.0 / (double)3.0;
2370 Editor::setup_toolbar ()
2374 const guint32 FUDGE = 18; // Combo's are stupid - they steal space from the entry for the button
2377 /* Mode Buttons (tool selection) */
2379 vector<ToggleButton *> mouse_mode_buttons;
2381 mouse_move_button.add (*(manage (new Image (::get_icon("tool_object")))));
2382 mouse_move_button.set_relief(Gtk::RELIEF_NONE);
2383 mouse_mode_buttons.push_back (&mouse_move_button);
2384 mouse_select_button.add (*(manage (new Image (get_xpm("tool_range.xpm")))));
2385 mouse_select_button.set_relief(Gtk::RELIEF_NONE);
2386 mouse_mode_buttons.push_back (&mouse_select_button);
2387 mouse_gain_button.add (*(manage (new Image (::get_icon("tool_gain")))));
2388 mouse_gain_button.set_relief(Gtk::RELIEF_NONE);
2389 mouse_mode_buttons.push_back (&mouse_gain_button);
2390 mouse_zoom_button.add (*(manage (new Image (::get_icon("tool_zoom")))));
2391 mouse_zoom_button.set_relief(Gtk::RELIEF_NONE);
2392 mouse_mode_buttons.push_back (&mouse_zoom_button);
2393 mouse_timefx_button.add (*(manage (new Image (::get_icon("tool_stretch")))));
2394 mouse_timefx_button.set_relief(Gtk::RELIEF_NONE);
2395 mouse_mode_buttons.push_back (&mouse_timefx_button);
2396 mouse_audition_button.add (*(manage (new Image (::get_icon("tool_audition")))));
2397 mouse_audition_button.set_relief(Gtk::RELIEF_NONE);
2398 mouse_note_button.add (*(manage (new Image (::get_icon("tool_note")))));
2399 mouse_note_button.set_relief(Gtk::RELIEF_NONE);
2400 mouse_mode_buttons.push_back (&mouse_note_button);
2401 mouse_mode_buttons.push_back (&mouse_audition_button);
2403 mouse_mode_button_set = new GroupedButtons (mouse_mode_buttons);
2405 HBox* mode_box = manage(new HBox);
2406 mode_box->set_border_width (2);
2407 mode_box->set_spacing(4);
2408 mouse_mode_button_box.set_spacing(1);
2409 mouse_mode_button_box.pack_start(mouse_move_button, true, true);
2410 mouse_mode_button_box.pack_start(mouse_select_button, true, true);
2411 mouse_mode_button_box.pack_start(mouse_zoom_button, true, true);
2412 mouse_mode_button_box.pack_start(mouse_gain_button, true, true);
2413 mouse_mode_button_box.pack_start(mouse_timefx_button, true, true);
2414 mouse_mode_button_box.pack_start(mouse_audition_button, true, true);
2415 mouse_mode_button_box.pack_start(mouse_note_button, true, true);
2416 mouse_mode_button_box.set_homogeneous(true);
2418 vector<string> edit_mode_strings;
2419 edit_mode_strings.push_back (edit_mode_to_string (Splice));
2420 edit_mode_strings.push_back (edit_mode_to_string (Slide));
2422 edit_mode_selector.set_name ("EditModeSelector");
2423 Gtkmm2ext::set_size_request_to_display_given_text (edit_mode_selector, longest (edit_mode_strings).c_str(), 2+FUDGE, 10);
2424 set_popdown_strings (edit_mode_selector, edit_mode_strings);
2425 edit_mode_selector.signal_changed().connect (mem_fun(*this, &Editor::edit_mode_selection_done));
2427 mode_box->pack_start(edit_mode_selector);
2428 mode_box->pack_start(mouse_mode_button_box);
2430 mouse_mode_tearoff = manage (new TearOff (*mode_box));
2431 mouse_mode_tearoff->set_name ("MouseModeBase");
2433 mouse_mode_tearoff->Detach.connect (bind (mem_fun(*this, &Editor::detach_tearoff), static_cast<Box*>(&toolbar_hbox),
2434 &mouse_mode_tearoff->tearoff_window()));
2435 mouse_mode_tearoff->Attach.connect (bind (mem_fun(*this, &Editor::reattach_tearoff), static_cast<Box*> (&toolbar_hbox),
2436 &mouse_mode_tearoff->tearoff_window(), 1));
2437 mouse_mode_tearoff->Hidden.connect (bind (mem_fun(*this, &Editor::detach_tearoff), static_cast<Box*>(&toolbar_hbox),
2438 &mouse_mode_tearoff->tearoff_window()));
2439 mouse_mode_tearoff->Visible.connect (bind (mem_fun(*this, &Editor::reattach_tearoff), static_cast<Box*> (&toolbar_hbox),
2440 &mouse_mode_tearoff->tearoff_window(), 1));
2442 mouse_move_button.set_name ("MouseModeButton");
2443 mouse_select_button.set_name ("MouseModeButton");
2444 mouse_gain_button.set_name ("MouseModeButton");
2445 mouse_zoom_button.set_name ("MouseModeButton");
2446 mouse_timefx_button.set_name ("MouseModeButton");
2447 mouse_audition_button.set_name ("MouseModeButton");
2448 mouse_note_button.set_name ("MouseModeButton");
2450 ARDOUR_UI::instance()->tooltips().set_tip (mouse_move_button, _("Select/Move Objects"));
2451 ARDOUR_UI::instance()->tooltips().set_tip (mouse_select_button, _("Select/Move Ranges"));
2452 ARDOUR_UI::instance()->tooltips().set_tip (mouse_gain_button, _("Draw Gain Automation"));
2453 ARDOUR_UI::instance()->tooltips().set_tip (mouse_zoom_button, _("Select Zoom Range"));
2454 ARDOUR_UI::instance()->tooltips().set_tip (mouse_timefx_button, _("Stretch/Shrink Regions"));
2455 ARDOUR_UI::instance()->tooltips().set_tip (mouse_audition_button, _("Listen to Specific Regions"));
2456 ARDOUR_UI::instance()->tooltips().set_tip (mouse_note_button, _("Edit MIDI Notes"));
2458 mouse_move_button.unset_flags (CAN_FOCUS);
2459 mouse_select_button.unset_flags (CAN_FOCUS);
2460 mouse_gain_button.unset_flags (CAN_FOCUS);
2461 mouse_zoom_button.unset_flags (CAN_FOCUS);
2462 mouse_timefx_button.unset_flags (CAN_FOCUS);
2463 mouse_audition_button.unset_flags (CAN_FOCUS);
2464 mouse_note_button.unset_flags (CAN_FOCUS);
2466 mouse_select_button.signal_toggled().connect (bind (mem_fun(*this, &Editor::mouse_mode_toggled), Editing::MouseRange));
2467 mouse_select_button.signal_button_release_event().connect (mem_fun(*this, &Editor::mouse_select_button_release));
2469 mouse_move_button.signal_toggled().connect (bind (mem_fun(*this, &Editor::mouse_mode_toggled), Editing::MouseObject));
2470 mouse_gain_button.signal_toggled().connect (bind (mem_fun(*this, &Editor::mouse_mode_toggled), Editing::MouseGain));
2471 mouse_zoom_button.signal_toggled().connect (bind (mem_fun(*this, &Editor::mouse_mode_toggled), Editing::MouseZoom));
2472 mouse_timefx_button.signal_toggled().connect (bind (mem_fun(*this, &Editor::mouse_mode_toggled), Editing::MouseTimeFX));
2473 mouse_audition_button.signal_toggled().connect (bind (mem_fun(*this, &Editor::mouse_mode_toggled), Editing::MouseAudition));
2474 mouse_note_button.signal_toggled().connect (bind (mem_fun(*this, &Editor::mouse_mode_toggled), Editing::MouseNote));
2476 // mouse_move_button.set_active (true);
2481 zoom_box.set_spacing (1);
2482 zoom_box.set_border_width (2);
2484 zoom_in_button.set_name ("EditorTimeButton");
2485 zoom_in_button.set_size_request(-1,16);
2486 zoom_in_button.add (*(manage (new Image (::get_icon("zoom_in")))));
2487 zoom_in_button.signal_clicked().connect (bind (mem_fun(*this, &Editor::temporal_zoom_step), false));
2488 ARDOUR_UI::instance()->tooltips().set_tip (zoom_in_button, _("Zoom In"));
2490 zoom_out_button.set_name ("EditorTimeButton");
2491 zoom_out_button.set_size_request(-1,16);
2492 zoom_out_button.add (*(manage (new Image (::get_icon("zoom_out")))));
2493 zoom_out_button.signal_clicked().connect (bind (mem_fun(*this, &Editor::temporal_zoom_step), true));
2494 ARDOUR_UI::instance()->tooltips().set_tip (zoom_out_button, _("Zoom Out"));
2496 zoom_out_full_button.set_name ("EditorTimeButton");
2497 zoom_out_full_button.set_size_request(-1,16);
2498 zoom_out_full_button.add (*(manage (new Image (::get_icon("zoom_full")))));
2499 zoom_out_full_button.signal_clicked().connect (mem_fun(*this, &Editor::temporal_zoom_session));
2500 ARDOUR_UI::instance()->tooltips().set_tip (zoom_out_full_button, _("Zoom to Session"));
2502 zoom_focus_selector.set_name ("ZoomFocusSelector");
2503 Gtkmm2ext::set_size_request_to_display_given_text (zoom_focus_selector, "Center", FUDGE, 0);
2504 set_popdown_strings (zoom_focus_selector, zoom_focus_strings);
2505 zoom_focus_selector.signal_changed().connect (mem_fun(*this, &Editor::zoom_focus_selection_done));
2506 ARDOUR_UI::instance()->tooltips().set_tip (zoom_focus_selector, _("Zoom focus"));
2508 zoom_box.pack_start (zoom_focus_selector, true, true);
2509 zoom_box.pack_start (zoom_out_button, false, false);
2510 zoom_box.pack_start (zoom_in_button, false, false);
2511 zoom_box.pack_start (zoom_out_full_button, false, false);
2513 /* Edit Cursor / Snap */
2515 snap_box.set_spacing (1);
2516 snap_box.set_border_width (2);
2518 snap_type_selector.set_name ("SnapTypeSelector");
2519 Gtkmm2ext::set_size_request_to_display_given_text (snap_type_selector, "SMPTE Seconds", 2+FUDGE, 10);
2520 set_popdown_strings (snap_type_selector, snap_type_strings);
2521 snap_type_selector.signal_changed().connect (mem_fun(*this, &Editor::snap_type_selection_done));
2522 ARDOUR_UI::instance()->tooltips().set_tip (snap_type_selector, _("Unit to snap cursors and ranges to"));
2524 snap_mode_selector.set_name ("SnapModeSelector");
2525 Gtkmm2ext::set_size_request_to_display_given_text (snap_mode_selector, "Magnetic Snap", 2+FUDGE, 10);
2526 set_popdown_strings (snap_mode_selector, snap_mode_strings);
2527 snap_mode_selector.signal_changed().connect (mem_fun(*this, &Editor::snap_mode_selection_done));
2529 snap_box.pack_start (edit_cursor_clock, false, false);
2530 snap_box.pack_start (snap_mode_selector, false, false);
2531 snap_box.pack_start (snap_type_selector, false, false);
2536 HBox *nudge_box = manage (new HBox);
2537 nudge_box->set_spacing(1);
2538 nudge_box->set_border_width (2);
2540 nudge_forward_button.signal_clicked().connect (bind (mem_fun(*this, &Editor::nudge_forward), false));
2541 nudge_backward_button.signal_clicked().connect (bind (mem_fun(*this, &Editor::nudge_backward), false));
2543 nudge_box->pack_start (nudge_backward_button, false, false);
2544 nudge_box->pack_start (nudge_forward_button, false, false);
2545 nudge_box->pack_start (nudge_clock, false, false);
2548 /* Pack everything in... */
2550 HBox* hbox = new HBox;
2551 hbox->set_spacing(10);
2553 tools_tearoff = new TearOff (*hbox);
2554 tools_tearoff->set_name ("MouseModeBase");
2556 tools_tearoff->Detach.connect (bind (mem_fun(*this, &Editor::detach_tearoff), static_cast<Box*>(&toolbar_hbox),
2557 &tools_tearoff->tearoff_window()));
2558 tools_tearoff->Attach.connect (bind (mem_fun(*this, &Editor::reattach_tearoff), static_cast<Box*> (&toolbar_hbox),
2559 &tools_tearoff->tearoff_window(), 0));
2560 tools_tearoff->Hidden.connect (bind (mem_fun(*this, &Editor::detach_tearoff), static_cast<Box*>(&toolbar_hbox),
2561 &tools_tearoff->tearoff_window()));
2562 tools_tearoff->Visible.connect (bind (mem_fun(*this, &Editor::reattach_tearoff), static_cast<Box*> (&toolbar_hbox),
2563 &tools_tearoff->tearoff_window(), 0));
2565 toolbar_hbox.set_spacing (10);
2566 toolbar_hbox.set_border_width (1);
2568 toolbar_hbox.pack_start (*mouse_mode_tearoff, false, false);
2569 toolbar_hbox.pack_start (*tools_tearoff, false, false);
2572 hbox->pack_start (snap_box, false, false);
2573 // hbox->pack_start (zoom_box, false, false);
2574 hbox->pack_start (*nudge_box, false, false);
2578 toolbar_base.set_name ("ToolBarBase");
2579 toolbar_base.add (toolbar_hbox);
2581 toolbar_frame.set_shadow_type (SHADOW_OUT);
2582 toolbar_frame.set_name ("BaseFrame");
2583 toolbar_frame.add (toolbar_base);
2588 Editor::setup_midi_toolbar ()
2592 /* Mode Buttons (tool selection) */
2594 vector<ToggleButton *> midi_tool_buttons;
2596 midi_tool_select_button.add (*(manage (new Image (::get_icon("midi_tool_select")))));
2597 midi_tool_select_button.set_relief(Gtk::RELIEF_NONE);
2598 midi_tool_buttons.push_back (&midi_tool_select_button);
2599 midi_tool_pencil_button.add (*(manage (new Image (::get_icon("midi_tool_pencil")))));
2600 midi_tool_pencil_button.set_relief(Gtk::RELIEF_NONE);
2601 midi_tool_buttons.push_back (&midi_tool_pencil_button);
2602 midi_tool_erase_button.add (*(manage (new Image (::get_icon("midi_tool_erase")))));
2603 midi_tool_erase_button.set_relief(Gtk::RELIEF_NONE);
2604 midi_tool_buttons.push_back (&midi_tool_erase_button);
2606 midi_tool_select_button.set_active(true);
2608 midi_tool_button_set = new GroupedButtons (midi_tool_buttons);
2610 midi_tool_button_box.set_border_width (2);
2611 midi_tool_button_box.set_spacing(4);
2612 midi_tool_button_box.set_spacing(1);
2613 midi_tool_button_box.pack_start(midi_tool_select_button, true, true);
2614 midi_tool_button_box.pack_start(midi_tool_pencil_button, true, true);
2615 midi_tool_button_box.pack_start(midi_tool_erase_button, true, true);
2616 midi_tool_button_box.set_homogeneous(true);
2618 midi_tool_select_button.set_name ("MouseModeButton");
2619 midi_tool_pencil_button.set_name ("MouseModeButton");
2620 midi_tool_erase_button.set_name ("MouseModeButton");
2622 ARDOUR_UI::instance()->tooltips().set_tip (midi_tool_select_button, _("Select/Move Notes"));
2623 ARDOUR_UI::instance()->tooltips().set_tip (midi_tool_pencil_button, _("Add/Move/Stretch Notes"));
2624 ARDOUR_UI::instance()->tooltips().set_tip (midi_tool_erase_button, _("Erase Notes"));
2626 midi_tool_select_button.unset_flags (CAN_FOCUS);
2627 midi_tool_pencil_button.unset_flags (CAN_FOCUS);
2628 midi_tool_erase_button.unset_flags (CAN_FOCUS);
2630 midi_tool_select_button.signal_toggled().connect (bind (mem_fun(*this,
2631 &Editor::midi_edit_mode_toggled), Editing::MidiEditSelect));
2632 midi_tool_pencil_button.signal_toggled().connect (bind (mem_fun(*this,
2633 &Editor::midi_edit_mode_toggled), Editing::MidiEditPencil));
2634 midi_tool_erase_button.signal_toggled().connect (bind (mem_fun(*this,
2635 &Editor::midi_edit_mode_toggled), Editing::MidiEditErase));
2637 /* Pack everything in... */
2639 midi_tools_tearoff = new TearOff (midi_tool_button_box);
2640 midi_tools_tearoff->set_name ("MouseModeBase");
2643 midi_tools_tearoff->Detach.connect (bind (mem_fun(*this, &Editor::detach_tearoff), static_cast<Box*>(&midi_toolbar_hbox),
2644 &midi_tools_tearoff->tearoff_window()));
2645 midi_tools_tearoff->Attach.connect (bind (mem_fun(*this, &Editor::reattach_tearoff), static_cast<Box*> (&midi_toolbar_hbox),
2646 &midi_tools_tearoff->tearoff_window(), 0));
2647 midi_tools_tearoff->Hidden.connect (bind (mem_fun(*this, &Editor::detach_tearoff), static_cast<Box*>(&midi_toolbar_hbox),
2648 &midi_tools_tearoff->tearoff_window()));
2649 midi_tools_tearoff->Visible.connect (bind (mem_fun(*this, &Editor::reattach_tearoff), static_cast<Box*> (&midi_toolbar_hbox),
2650 &midi_tools_tearoff->tearoff_window(), 0));
2653 midi_toolbar_hbox.set_spacing (10);
2654 midi_toolbar_hbox.set_border_width (1);
2656 midi_toolbar_hbox.pack_start (*midi_tools_tearoff, false, true);
2658 midi_tool_button_box.show_all ();
2659 midi_toolbar_hbox.show_all();
2660 midi_tools_tearoff->show_all();
2662 midi_toolbar_base.set_name ("ToolBarBase");
2663 midi_toolbar_base.add (midi_toolbar_hbox);
2665 midi_toolbar_frame.set_shadow_type (SHADOW_OUT);
2666 midi_toolbar_frame.set_name ("BaseFrame");
2667 midi_toolbar_frame.add (midi_toolbar_base);
2671 Editor::convert_drop_to_paths (vector<ustring>& paths,
2672 const RefPtr<Gdk::DragContext>& context,
2675 const SelectionData& data,
2684 vector<ustring> uris = data.get_uris();
2688 /* This is seriously fucked up. Nautilus doesn't say that its URI lists
2689 are actually URI lists. So do it by hand.
2692 if (data.get_target() != "text/plain") {
2696 /* Parse the "uri-list" format that Nautilus provides,
2697 where each pathname is delimited by \r\n
2700 const char* p = data.get_text().c_str();
2707 while (g_ascii_isspace (*p))
2711 while (*q && (*q != '\n') && (*q != '\r'))
2717 while (q > p && g_ascii_isspace (*q))
2722 uris.push_back (ustring (p, q - p + 1));
2726 p = strchr (p, '\n');
2736 for (vector<ustring>::iterator i = uris.begin(); i != uris.end(); ++i) {
2737 if ((*i).substr (0,7) == "file://") {
2739 PBD::url_decode (p);
2740 paths.push_back (p.substr (7));
2748 Editor::new_tempo_section ()
2754 Editor::map_transport_state ()
2756 ENSURE_GUI_THREAD (mem_fun(*this, &Editor::map_transport_state));
2758 if (session->transport_stopped()) {
2759 have_pending_keyboard_selection = false;
2762 update_loop_range_view (true);
2767 Editor::State::State ()
2769 selection = new Selection;
2772 Editor::State::~State ()
2778 Editor::get_memento () const
2780 State *state = new State;
2782 store_state (*state);
2783 return bind (mem_fun (*(const_cast<Editor*>(this)), &Editor::restore_state), state);
2787 Editor::store_state (State& state) const
2789 *state.selection = *selection;
2793 Editor::restore_state (State *state)
2795 if (*selection == *state->selection) {
2799 *selection = *state->selection;
2800 time_selection_changed ();
2801 region_selection_changed ();
2803 /* XXX other selection change handlers? */
2807 Editor::begin_reversible_command (string name)
2810 before = &get_state();
2811 session->begin_reversible_command (name);
2816 Editor::commit_reversible_command ()
2819 session->commit_reversible_command (new MementoCommand<Editor>(*this, before, &get_state()));
2824 Editor::set_edit_group_solo (Route& route, bool yn)
2826 RouteGroup *edit_group;
2828 if ((edit_group = route.edit_group()) != 0) {
2829 edit_group->apply (&Route::set_solo, yn, this);
2831 route.set_solo (yn, this);
2836 Editor::set_edit_group_mute (Route& route, bool yn)
2838 RouteGroup *edit_group = 0;
2840 if ((edit_group == route.edit_group()) != 0) {
2841 edit_group->apply (&Route::set_mute, yn, this);
2843 route.set_mute (yn, this);
2848 Editor::history_changed ()
2852 if (undo_action && session) {
2853 if (session->undo_depth() == 0) {
2856 label = string_compose(_("Undo (%1)"), session->next_undo());
2858 undo_action->property_label() = label;
2861 if (redo_action && session) {
2862 if (session->redo_depth() == 0) {
2865 label = string_compose(_("Redo (%1)"), session->next_redo());
2867 redo_action->property_label() = label;
2872 Editor::duplicate_dialog (bool dup_region)
2874 if (selection->regions.empty() && (selection->time.length() == 0)) {
2878 ArdourDialog win ("duplicate dialog");
2879 Label label (_("Duplicate how many times?"));
2880 Adjustment adjustment (1.0, 1.0, 1000000.0, 1.0, 5.0);
2881 SpinButton spinner (adjustment);
2883 win.get_vbox()->set_spacing (12);
2884 win.get_vbox()->pack_start (label);
2886 /* dialogs have ::add_action_widget() but that puts the spinner in the wrong
2887 place, visually. so do this by hand.
2890 win.get_vbox()->pack_start (spinner);
2891 spinner.signal_activate().connect (sigc::bind (mem_fun (win, &ArdourDialog::response), RESPONSE_ACCEPT));
2896 win.add_button (Stock::OK, RESPONSE_ACCEPT);
2897 win.add_button (Stock::CANCEL, RESPONSE_CANCEL);
2899 win.set_position (WIN_POS_MOUSE);
2901 spinner.grab_focus ();
2903 switch (win.run ()) {
2904 case RESPONSE_ACCEPT:
2910 float times = adjustment.get_value();
2912 if (!selection->regions.empty()) {
2913 duplicate_some_regions (selection->regions, times);
2915 duplicate_selection (times);
2920 Editor::show_verbose_canvas_cursor ()
2922 verbose_canvas_cursor->raise_to_top();
2923 verbose_canvas_cursor->show();
2924 verbose_cursor_visible = true;
2928 Editor::hide_verbose_canvas_cursor ()
2930 verbose_canvas_cursor->hide();
2931 verbose_cursor_visible = false;
2935 Editor::set_verbose_canvas_cursor (const string & txt, double x, double y)
2937 /* XXX get origin of canvas relative to root window,
2938 add x and y and check compared to gdk_screen_{width,height}
2940 verbose_canvas_cursor->property_text() = txt.c_str();
2941 verbose_canvas_cursor->property_x() = x;
2942 verbose_canvas_cursor->property_y() = y;
2946 Editor::set_verbose_canvas_cursor_text (const string & txt)
2948 verbose_canvas_cursor->property_text() = txt.c_str();
2952 Editor::edit_mode_selection_done ()
2958 string choice = edit_mode_selector.get_active_text();
2959 EditMode mode = Slide;
2961 if (choice == _("Splice Edit")) {
2963 } else if (choice == _("Slide Edit")) {
2967 Config->set_edit_mode (mode);
2971 Editor::snap_type_selection_done ()
2973 string choice = snap_type_selector.get_active_text();
2974 SnapType snaptype = SnapToFrame;
2976 if (choice == _("Beats/3")) {
2977 snaptype = SnapToAThirdBeat;
2978 } else if (choice == _("Beats/4")) {
2979 snaptype = SnapToAQuarterBeat;
2980 } else if (choice == _("Beats/8")) {
2981 snaptype = SnapToAEighthBeat;
2982 } else if (choice == _("Beats/16")) {
2983 snaptype = SnapToASixteenthBeat;
2984 } else if (choice == _("Beats/32")) {
2985 snaptype = SnapToAThirtysecondBeat;
2986 } else if (choice == _("Beats")) {
2987 snaptype = SnapToBeat;
2988 } else if (choice == _("Bars")) {
2989 snaptype = SnapToBar;
2990 } else if (choice == _("Marks")) {
2991 snaptype = SnapToMark;
2992 } else if (choice == _("Edit Cursor")) {
2993 snaptype = SnapToEditCursor;
2994 } else if (choice == _("Region starts")) {
2995 snaptype = SnapToRegionStart;
2996 } else if (choice == _("Region ends")) {
2997 snaptype = SnapToRegionEnd;
2998 } else if (choice == _("Region bounds")) {
2999 snaptype = SnapToRegionBoundary;
3000 } else if (choice == _("Region syncs")) {
3001 snaptype = SnapToRegionSync;
3002 } else if (choice == _("CD Frames")) {
3003 snaptype = SnapToCDFrame;
3004 } else if (choice == _("SMPTE Frames")) {
3005 snaptype = SnapToSMPTEFrame;
3006 } else if (choice == _("SMPTE Seconds")) {
3007 snaptype = SnapToSMPTESeconds;
3008 } else if (choice == _("SMPTE Minutes")) {
3009 snaptype = SnapToSMPTEMinutes;
3010 } else if (choice == _("Seconds")) {
3011 snaptype = SnapToSeconds;
3012 } else if (choice == _("Minutes")) {
3013 snaptype = SnapToMinutes;
3014 } else if (choice == _("None")) {
3015 snaptype = SnapToFrame;
3018 RefPtr<RadioAction> ract = snap_type_action (snaptype);
3020 ract->set_active ();
3025 Editor::snap_mode_selection_done ()
3027 string choice = snap_mode_selector.get_active_text();
3028 SnapMode mode = SnapNormal;
3030 if (choice == _("Normal")) {
3032 } else if (choice == _("Magnetic")) {
3033 mode = SnapMagnetic;
3036 RefPtr<RadioAction> ract = snap_mode_action (mode);
3039 ract->set_active (true);
3044 Editor::zoom_focus_selection_done ()
3046 string choice = zoom_focus_selector.get_active_text();
3047 ZoomFocus focus_type = ZoomFocusLeft;
3049 if (choice == _("Left")) {
3050 focus_type = ZoomFocusLeft;
3051 } else if (choice == _("Right")) {
3052 focus_type = ZoomFocusRight;
3053 } else if (choice == _("Center")) {
3054 focus_type = ZoomFocusCenter;
3055 } else if (choice == _("Play")) {
3056 focus_type = ZoomFocusPlayhead;
3057 } else if (choice == _("Edit")) {
3058 focus_type = ZoomFocusEdit;
3061 RefPtr<RadioAction> ract = zoom_focus_action (focus_type);
3064 ract->set_active ();
3069 Editor::edit_controls_button_release (GdkEventButton* ev)
3071 if (Keyboard::is_context_menu_event (ev)) {
3072 ARDOUR_UI::instance()->add_route (this);
3078 Editor::mouse_select_button_release (GdkEventButton* ev)
3080 /* this handles just right-clicks */
3082 if (ev->button != 3) {
3089 Editor::TrackViewList *
3090 Editor::get_valid_views (TimeAxisView* track, RouteGroup* group)
3093 TrackViewList::iterator i;
3095 v = new TrackViewList;
3097 if (track == 0 && group == 0) {
3101 for (i = track_views.begin(); i != track_views.end (); ++i) {
3105 } else if (track != 0 && group == 0 || (track != 0 && group != 0 && !group->is_active())) {
3107 /* just the view for this track
3110 v->push_back (track);
3114 /* views for all tracks in the edit group */
3116 for (i = track_views.begin(); i != track_views.end (); ++i) {
3118 if (group == 0 || (*i)->edit_group() == group) {
3128 Editor::set_zoom_focus (ZoomFocus f)
3130 string str = zoom_focus_strings[(int)f];
3132 if (str != zoom_focus_selector.get_active_text()) {
3133 zoom_focus_selector.set_active_text (str);
3136 if (zoom_focus != f) {
3139 ZoomFocusChanged (); /* EMIT_SIGNAL */
3146 Editor::ensure_float (Window& win)
3148 win.set_transient_for (*this);
3152 Editor::pane_allocation_handler (Allocation &alloc, Paned* which)
3154 /* recover or initialize pane positions. do this here rather than earlier because
3155 we don't want the positions to change the child allocations, which they seem to do.
3161 XMLNode* node = ARDOUR_UI::instance()->editor_settings();
3163 static int32_t done;
3166 if ((geometry = find_named_node (*node, "geometry")) == 0) {
3167 width = default_width;
3168 height = default_height;
3170 width = atoi(geometry->property("x_size")->value());
3171 height = atoi(geometry->property("y_size")->value());
3174 if (which == static_cast<Paned*> (&edit_pane)) {
3180 if (!geometry || (prop = geometry->property ("edit_pane_pos")) == 0) {
3181 /* initial allocation is 90% to canvas, 10% to notebook */
3182 pos = (int) floor (alloc.get_width() * 0.90f);
3183 snprintf (buf, sizeof(buf), "%d", pos);
3185 pos = atoi (prop->value());
3188 if ((done = GTK_WIDGET(edit_pane.gobj())->allocation.width > pos)) {
3189 edit_pane.set_position (pos);
3190 pre_maximal_pane_position = pos;
3196 Editor::detach_tearoff (Box* b, Window* w)
3198 if (tools_tearoff->torn_off() &&
3199 mouse_mode_tearoff->torn_off()) {
3200 top_hbox.remove (toolbar_frame);
3205 Editor::reattach_tearoff (Box* b, Window* w, int32_t n)
3207 if (toolbar_frame.get_parent() == 0) {
3208 top_hbox.pack_end (toolbar_frame);
3213 Editor::set_show_measures (bool yn)
3215 if (_show_measures != yn) {
3218 if ((_show_measures = yn) == true) {
3226 Editor::toggle_follow_playhead ()
3228 RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("toggle-follow-playhead"));
3230 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
3231 set_follow_playhead (tact->get_active());
3236 Editor::set_follow_playhead (bool yn)
3238 if (_follow_playhead != yn) {
3239 if ((_follow_playhead = yn) == true) {
3241 update_current_screen ();
3248 Editor::toggle_xfade_active (boost::weak_ptr<Crossfade> wxfade)
3250 boost::shared_ptr<Crossfade> xfade (wxfade.lock());
3252 xfade->set_active (!xfade->active());
3257 Editor::toggle_xfade_length (boost::weak_ptr<Crossfade> wxfade)
3259 boost::shared_ptr<Crossfade> xfade (wxfade.lock());
3261 xfade->set_follow_overlap (!xfade->following_overlap());
3266 Editor::edit_xfade (boost::weak_ptr<Crossfade> wxfade)
3268 boost::shared_ptr<Crossfade> xfade (wxfade.lock());
3274 CrossfadeEditor cew (*session, xfade, xfade->fade_in().get_min_y(), 1.0);
3278 switch (cew.run ()) {
3279 case RESPONSE_ACCEPT:
3286 xfade->StateChanged (Change (~0));
3290 Editor::playlist_selector () const
3292 return *_playlist_selector;
3296 Editor::get_nudge_distance (nframes_t pos, nframes_t& next)
3300 ret = nudge_clock.current_duration (pos);
3301 next = ret + 1; /* XXXX fix me */
3307 Editor::end_location_changed (Location* location)
3309 ENSURE_GUI_THREAD (bind (mem_fun(*this, &Editor::end_location_changed), location));
3310 reset_scrolling_region ();
3314 Editor::playlist_deletion_dialog (boost::shared_ptr<Playlist> pl)
3316 ArdourDialog dialog ("playlist deletion dialog");
3317 Label label (string_compose (_("Playlist %1 is currently unused.\n"
3318 "If left alone, no audio files used by it will be cleaned.\n"
3319 "If deleted, audio files used by it alone by will cleaned."),
3322 dialog.set_position (WIN_POS_CENTER);
3323 dialog.get_vbox()->pack_start (label);
3327 dialog.add_button (_("Delete playlist"), RESPONSE_ACCEPT);
3328 dialog.add_button (_("Keep playlist"), RESPONSE_REJECT);
3329 dialog.add_button (_("Cancel"), RESPONSE_CANCEL);
3331 switch (dialog.run ()) {
3332 case RESPONSE_ACCEPT:
3333 /* delete the playlist */
3337 case RESPONSE_REJECT:
3338 /* keep the playlist */
3350 Editor::audio_region_selection_covers (nframes_t where)
3352 for (RegionSelection::iterator a = selection->regions.begin(); a != selection->regions.end(); ++a) {
3353 if ((*a)->region()->covers (where)) {
3362 Editor::prepare_for_cleanup ()
3364 cut_buffer->clear_regions ();
3365 cut_buffer->clear_playlists ();
3367 selection->clear_regions ();
3368 selection->clear_playlists ();
3372 Editor::transport_loop_location()
3375 return session->locations()->auto_loop_location();
3382 Editor::transport_punch_location()
3385 return session->locations()->auto_punch_location();
3392 Editor::control_layout_scroll (GdkEventScroll* ev)
3394 switch (ev->direction) {
3396 scroll_tracks_up_line ();
3400 case GDK_SCROLL_DOWN:
3401 scroll_tracks_down_line ();
3405 /* no left/right handling yet */
3413 /** A new snapshot has been selected.
3416 Editor::snapshot_display_selection_changed ()
3418 if (snapshot_display.get_selection()->count_selected_rows() > 0) {
3420 TreeModel::iterator i = snapshot_display.get_selection()->get_selected();
3422 Glib::ustring snap_name = (*i)[snapshot_display_columns.real_name];
3424 if (snap_name.length() == 0) {
3428 if (session->snap_name() == snap_name) {
3432 ARDOUR_UI::instance()->load_session(session->path(), string (snap_name));
3437 Editor::snapshot_display_button_press (GdkEventButton* ev)
3439 if (ev->button == 3) {
3440 /* Right-click on the snapshot list. Work out which snapshot it
3442 Gtk::TreeModel::Path path;
3443 Gtk::TreeViewColumn* col;
3446 snapshot_display.get_path_at_pos ((int) ev->x, (int) ev->y, path, col, cx, cy);
3447 Gtk::TreeModel::iterator iter = snapshot_display_model->get_iter (path);
3449 Gtk::TreeModel::Row row = *iter;
3450 popup_snapshot_context_menu (ev->button, ev->time, row[snapshot_display_columns.real_name]);
3459 /** Pop up the snapshot display context menu.
3460 * @param button Button used to open the menu.
3461 * @param time Menu open time.
3462 * @snapshot_name Name of the snapshot that the menu click was over.
3466 Editor::popup_snapshot_context_menu (int button, int32_t time, Glib::ustring snapshot_name)
3468 using namespace Menu_Helpers;
3470 MenuList& items (snapshot_context_menu.items());
3473 const bool modification_allowed = (session->snap_name() != snapshot_name && session->name() != snapshot_name);
3475 add_item_with_sensitivity (items, MenuElem (_("Remove"), bind (mem_fun (*this, &Editor::remove_snapshot), snapshot_name)), modification_allowed);
3477 add_item_with_sensitivity (items, MenuElem (_("Rename"), bind (mem_fun (*this, &Editor::rename_snapshot), snapshot_name)), modification_allowed);
3479 snapshot_context_menu.popup (button, time);
3483 Editor::rename_snapshot (Glib::ustring old_name)
3485 ArdourPrompter prompter(true);
3489 prompter.set_name ("Prompter");
3490 prompter.add_button (Gtk::Stock::SAVE, Gtk::RESPONSE_ACCEPT);
3491 prompter.set_prompt (_("New name of snapshot"));
3492 prompter.set_initial_text (old_name);
3494 if (prompter.run() == RESPONSE_ACCEPT) {
3495 prompter.get_result (new_name);
3496 if (new_name.length()) {
3497 session->rename_state (old_name, new_name);
3498 redisplay_snapshots ();
3505 Editor::remove_snapshot (Glib::ustring name)
3507 vector<string> choices;
3509 std::string prompt = string_compose (_("Do you really want to remove snapshot \"%1\" ?\n(cannot be undone)"), name);
3511 choices.push_back (_("No, do nothing."));
3512 choices.push_back (_("Yes, remove it."));
3514 Gtkmm2ext::Choice prompter (prompt, choices);
3516 if (prompter.run () == 1) {
3517 session->remove_state (name);
3518 redisplay_snapshots ();
3523 Editor::redisplay_snapshots ()
3529 vector<string*>* states;
3531 if ((states = session->possible_states()) == 0) {
3535 snapshot_display_model->clear ();
3537 for (vector<string*>::iterator i = states->begin(); i != states->end(); ++i) {
3538 string statename = *(*i);
3539 TreeModel::Row row = *(snapshot_display_model->append());
3541 /* this lingers on in case we ever want to change the visible
3542 name of the snapshot.
3545 string display_name;
3546 display_name = statename;
3548 if (statename == session->snap_name()) {
3549 snapshot_display.get_selection()->select(row);
3552 row[snapshot_display_columns.visible_name] = display_name;
3553 row[snapshot_display_columns.real_name] = statename;
3560 Editor::session_state_saved (string snap_name)
3562 ENSURE_GUI_THREAD (bind (mem_fun(*this, &Editor::session_state_saved), snap_name));
3563 redisplay_snapshots ();
3567 Editor::maximise_editing_space ()
3569 initial_ruler_update_required = true;
3571 mouse_mode_tearoff->set_visible (false);
3572 tools_tearoff->set_visible (false);
3574 pre_maximal_pane_position = edit_pane.get_position();
3575 pre_maximal_editor_width = this->get_width();
3577 if(post_maximal_pane_position == 0) {
3578 post_maximal_pane_position = edit_pane.get_width();
3583 if(post_maximal_editor_width) {
3584 edit_pane.set_position (post_maximal_pane_position -
3585 abs(post_maximal_editor_width - pre_maximal_editor_width));
3587 edit_pane.set_position (post_maximal_pane_position);
3592 Editor::restore_editing_space ()
3594 initial_ruler_update_required = true;
3596 // user changed width of pane during fullscreen
3597 if(post_maximal_pane_position != edit_pane.get_position()) {
3598 post_maximal_pane_position = edit_pane.get_position();
3603 mouse_mode_tearoff->set_visible (true);
3604 tools_tearoff->set_visible (true);
3605 post_maximal_editor_width = this->get_width();
3608 edit_pane.set_position (
3609 pre_maximal_pane_position + abs(this->get_width() - pre_maximal_editor_width)
3614 Editor::new_playlists ()
3616 begin_reversible_command (_("new playlists"));
3617 mapover_tracks (mem_fun (*this, &Editor::mapped_use_new_playlist));
3618 commit_reversible_command ();
3622 Editor::copy_playlists ()
3624 begin_reversible_command (_("copy playlists"));
3625 mapover_tracks (mem_fun (*this, &Editor::mapped_use_copy_playlist));
3626 commit_reversible_command ();
3630 Editor::clear_playlists ()
3632 begin_reversible_command (_("clear playlists"));
3633 mapover_tracks (mem_fun (*this, &Editor::mapped_clear_playlist));
3634 commit_reversible_command ();
3638 Editor::mapped_use_new_playlist (RouteTimeAxisView& atv, uint32_t sz)
3640 atv.use_new_playlist (sz > 1 ? false : true);
3644 Editor::mapped_use_copy_playlist (RouteTimeAxisView& atv, uint32_t sz)
3646 atv.use_copy_playlist (sz > 1 ? false : true);
3650 Editor::mapped_clear_playlist (RouteTimeAxisView& atv, uint32_t sz)
3652 atv.clear_playlist ();
3656 Editor::on_key_press_event (GdkEventKey* ev)
3658 return key_press_focus_accelerator_handler (*this, ev);
3662 Editor::reset_x_origin (nframes_t frame)
3664 queue_visual_change (frame);
3668 Editor::reset_zoom (double fpu)
3670 queue_visual_change (fpu);
3674 Editor::reposition_and_zoom (nframes_t frame, double fpu)
3676 reset_x_origin (frame);
3681 Editor::set_frames_per_unit (double fpu)
3685 /* this is the core function that controls the zoom level of the canvas. it is called
3686 whenever one or more calls are made to reset_zoom(). it executes in an idle handler.
3689 if (fpu == frames_per_unit) {
3697 // convert fpu to frame count
3699 frames = (nframes_t) floor (fpu * canvas_width);
3701 /* don't allow zooms that fit more than the maximum number
3702 of frames into an 800 pixel wide space.
3705 if (max_frames / fpu < 800.0) {
3709 if (fpu == frames_per_unit) {
3713 frames_per_unit = fpu;
3715 if (frames != zoom_range_clock.current_duration()) {
3716 zoom_range_clock.set (frames);
3719 if (mouse_mode == MouseRange && selection->time.start () != selection->time.end_frame ()) {
3720 if (!selection->tracks.empty()) {
3721 for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
3722 (*i)->reshow_selection (selection->time);
3725 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
3726 (*i)->reshow_selection (selection->time);
3731 ZoomChanged (); /* EMIT_SIGNAL */
3733 reset_hscrollbar_stepping ();
3734 reset_scrolling_region ();
3736 if (edit_cursor) edit_cursor->set_position (edit_cursor->current_frame);
3737 if (playhead_cursor) playhead_cursor->set_position (playhead_cursor->current_frame);
3743 Editor::queue_visual_change (nframes_t where)
3745 pending_visual_change.pending = VisualChange::Type (pending_visual_change.pending | VisualChange::TimeOrigin);
3746 pending_visual_change.time_origin = where;
3748 if (pending_visual_change.idle_handler_id < 0) {
3749 pending_visual_change.idle_handler_id = g_idle_add (_idle_visual_changer, this);
3754 Editor::queue_visual_change (double fpu)
3756 pending_visual_change.pending = VisualChange::Type (pending_visual_change.pending | VisualChange::ZoomLevel);
3757 pending_visual_change.frames_per_unit = fpu;
3759 if (pending_visual_change.idle_handler_id < 0) {
3760 pending_visual_change.idle_handler_id = g_idle_add_full (G_PRIORITY_HIGH_IDLE, _idle_visual_changer, this, 0);
3765 Editor::_idle_visual_changer (void* arg)
3767 return static_cast<Editor*>(arg)->idle_visual_changer ();
3771 Editor::idle_visual_changer ()
3773 VisualChange::Type p = pending_visual_change.pending;
3775 pending_visual_change.pending = (VisualChange::Type) 0;
3776 pending_visual_change.idle_handler_id = -1;
3778 if (p & VisualChange::ZoomLevel) {
3779 set_frames_per_unit (pending_visual_change.frames_per_unit);
3782 if (p & VisualChange::TimeOrigin) {
3783 if (pending_visual_change.time_origin != leftmost_frame) {
3784 horizontal_adjustment.set_value (pending_visual_change.time_origin/frames_per_unit);
3785 /* the signal handler will do the rest */
3787 update_fixed_rulers();
3788 redisplay_tempo (true);
3792 return 0; /* this is always a one-shot call */
3795 struct EditorOrderTimeAxisSorter {
3796 bool operator() (const TimeAxisView* a, const TimeAxisView* b) const {
3797 return a->order < b->order;
3802 Editor::sort_track_selection ()
3804 EditorOrderTimeAxisSorter cmp;
3805 selection->tracks.sort (cmp);
3809 Editor::edit_cursor_position(bool sync)
3811 if (sync && edit_cursor->current_frame != edit_cursor_clock.current_time()) {
3812 edit_cursor_clock.set(edit_cursor->current_frame, true);
3815 return edit_cursor->current_frame;