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.
27 #include <boost/none.hpp>
29 #include <sigc++/bind.h>
31 #include <pbd/convert.h>
32 #include <pbd/error.h>
33 #include <pbd/enumwriter.h>
34 #include <pbd/memento_command.h>
36 #include <glibmm/miscutils.h>
37 #include <gtkmm/image.h>
38 #include <gdkmm/color.h>
39 #include <gdkmm/bitmap.h>
41 #include <gtkmm2ext/grouped_buttons.h>
42 #include <gtkmm2ext/gtk_ui.h>
43 #include <gtkmm2ext/tearoff.h>
44 #include <gtkmm2ext/utils.h>
45 #include <gtkmm2ext/window_title.h>
46 #include <gtkmm2ext/choice.h>
48 #include <ardour/audio_track.h>
49 #include <ardour/audio_diskstream.h>
50 #include <ardour/plugin_manager.h>
51 #include <ardour/location.h>
52 #include <ardour/audioplaylist.h>
53 #include <ardour/audioregion.h>
54 #include <ardour/region.h>
55 #include <ardour/session_route.h>
56 #include <ardour/tempo.h>
57 #include <ardour/utils.h>
58 #include <ardour/profile.h>
60 #include <control_protocol/control_protocol.h>
62 #include "ardour_ui.h"
66 #include "playlist_selector.h"
67 #include "audio_region_view.h"
68 #include "rgb_macros.h"
69 #include "selection.h"
70 #include "audio_streamview.h"
71 #include "time_axis_view.h"
72 #include "audio_time_axis.h"
74 #include "crossfade_view.h"
76 #include "public_editor.h"
77 #include "crossfade_edit.h"
78 #include "canvas_impl.h"
80 #include "gui_thread.h"
84 #include "analysis_window.h"
90 #include "imageframe_socket_handler.h"
91 /* </CMT Additions> */
95 using namespace ARDOUR;
99 using namespace Gtkmm2ext;
100 using namespace Editing;
104 const double Editor::timebar_height = 15.0;
106 #include "editor_xpms"
108 static const gchar *_snap_type_strings[] = {
132 static const gchar *_snap_mode_strings[] = {
138 static const gchar *_zoom_focus_strings[] = {
147 /* Soundfile drag-n-drop */
149 Gdk::Cursor* Editor::cross_hair_cursor = 0;
150 Gdk::Cursor* Editor::selector_cursor = 0;
151 Gdk::Cursor* Editor::trimmer_cursor = 0;
152 Gdk::Cursor* Editor::grabber_cursor = 0;
153 Gdk::Cursor* Editor::zoom_cursor = 0;
154 Gdk::Cursor* Editor::time_fx_cursor = 0;
155 Gdk::Cursor* Editor::fader_cursor = 0;
156 Gdk::Cursor* Editor::speaker_cursor = 0;
157 Gdk::Cursor* Editor::wait_cursor = 0;
158 Gdk::Cursor* Editor::timebar_cursor = 0;
161 show_me_the_size (Requisition* r, const char* what)
163 cerr << "size of " << what << " = " << r->width << " x " << r->height << endl;
167 check_adjustment (Gtk::Adjustment* adj)
169 cerr << "CHANGE adj = "
170 << adj->get_lower () << ' '
171 << adj->get_upper () << ' '
172 << adj->get_value () << ' '
173 << adj->get_step_increment () << ' '
174 << adj->get_page_increment () << ' '
175 << adj->get_page_size () << ' '
182 /* time display buttons */
183 minsec_label (_("Mins:Secs")),
184 bbt_label (_("Bars:Beats")),
185 smpte_label (_("Timecode")),
186 frame_label (_("Frames")),
187 tempo_label (_("Tempo")),
188 meter_label (_("Meter")),
189 mark_label (_("Location Markers")),
190 range_mark_label (_("Range Markers")),
191 transport_mark_label (_("Loop/Punch Ranges")),
193 edit_packer (3, 3, false),
195 /* the values here don't matter: layout widgets
196 reset them as needed.
199 vertical_adjustment (0.0, 0.0, 10.0, 400.0),
200 horizontal_adjustment (0.0, 0.0, 20.0, 1200.0),
202 /* tool bar related */
204 edit_cursor_clock (X_("editcursor"), false, X_("EditCursorClock"), true),
205 zoom_range_clock (X_("zoomrange"), false, X_("ZoomRangeClock"), true, true),
207 toolbar_selection_clock_table (2,3),
209 automation_mode_button (_("mode")),
210 global_automation_button (_("automation")),
212 /* <CMT Additions> */
213 image_socket_listener(0),
214 /* </CMT Additions> */
218 nudge_clock (X_("nudge"), false, X_("NudgeClock"), true, true)
223 /* we are a singleton */
225 PublicEditor::_instance = this;
229 selection = new Selection;
230 cut_buffer = new Selection;
232 selection->TimeChanged.connect (mem_fun(*this, &Editor::time_selection_changed));
233 selection->TracksChanged.connect (mem_fun(*this, &Editor::track_selection_changed));
234 selection->RegionsChanged.connect (mem_fun(*this, &Editor::region_selection_changed));
235 selection->PointsChanged.connect (mem_fun(*this, &Editor::point_selection_changed));
237 clicked_regionview = 0;
238 clicked_trackview = 0;
239 clicked_audio_trackview = 0;
240 clicked_crossfadeview = 0;
241 clicked_control_point = 0;
242 latest_regionview = 0;
243 last_update_frame = 0;
245 current_mixer_strip = 0;
246 current_bbt_points = 0;
248 snap_type_strings = I18N (_snap_type_strings);
249 snap_mode_strings = I18N (_snap_mode_strings);
250 zoom_focus_strings = I18N(_zoom_focus_strings);
252 snap_type = SnapToFrame;
253 set_snap_to (snap_type);
254 snap_mode = SnapNormal;
255 set_snap_mode (snap_mode);
256 snap_threshold = 5.0;
257 bbt_beat_subdivision = 4;
260 autoscroll_active = false;
261 autoscroll_timeout_tag = -1;
262 interthread_progress_window = 0;
268 current_interthread_info = 0;
269 _show_measures = true;
270 _show_waveforms = true;
271 _show_waveforms_recording = true;
272 first_action_message = 0;
274 export_range_markers_dialog = 0;
275 show_gain_after_trim = false;
276 ignore_route_list_reorder = false;
277 no_route_list_redisplay = false;
278 verbose_cursor_on = true;
279 route_removal = false;
280 show_automatic_regions_in_region_list = true;
281 region_list_sort_type = (Editing::RegionListSortType) 0;
282 have_pending_keyboard_selection = false;
283 _follow_playhead = true;
284 _xfade_visibility = true;
285 editor_ruler_menu = 0;
286 no_ruler_shown_update = false;
287 edit_group_list_menu = 0;
289 region_list_menu = 0;
291 start_end_marker_menu = 0;
292 range_marker_menu = 0;
293 marker_menu_item = 0;
295 transport_marker_menu = 0;
296 new_transport_marker_menu = 0;
297 editor_mixer_strip_width = Wide;
298 show_editor_mixer_when_tracks_arrive = false;
299 region_edit_menu_split_item = 0;
301 region_edit_menu_split_multichannel_item = 0;
303 ignore_mouse_mode_toggle = false;
304 current_stepping_trackview = 0;
306 entered_regionview = 0;
307 clear_entered_track = false;
308 _new_regionviews_show_envelope = false;
309 current_timestretch = 0;
310 in_edit_group_row_change = false;
311 last_canvas_frame = 0;
314 button_release_can_deselect = true;
315 canvas_idle_queued = false;
316 _dragging_playhead = false;
317 _dragging_hscrollbar = false;
321 mouse_speed_update = -1;
322 mouse_speed_size = 16;
323 mouse_speed = new double[mouse_speed_size];
324 memset (mouse_speed, 0, sizeof(double) * mouse_speed_size);
325 mouse_speed_entries = 0;
328 ignore_route_order_sync = false;
330 location_marker_color = ARDOUR_UI::config()->canvasvar_LocationMarker.get();
331 location_range_color = ARDOUR_UI::config()->canvasvar_LocationRange.get();
332 location_cd_marker_color = ARDOUR_UI::config()->canvasvar_LocationCDMarker.get();
333 location_loop_color = ARDOUR_UI::config()->canvasvar_LocationLoop.get();
334 location_punch_color = ARDOUR_UI::config()->canvasvar_LocationPunch.get();
336 range_marker_drag_rect = 0;
337 marker_drag_line = 0;
339 set_mouse_mode (MouseObject, true);
341 frames_per_unit = 2048; /* too early to use reset_zoom () */
342 reset_hscrollbar_stepping ();
344 zoom_focus = ZoomFocusLeft;
345 set_zoom_focus (ZoomFocusLeft);
346 zoom_range_clock.ValueChanged.connect (mem_fun(*this, &Editor::zoom_adjustment_changed));
348 initialize_rulers ();
349 initialize_canvas ();
351 edit_controls_vbox.set_spacing (0);
352 horizontal_adjustment.signal_value_changed().connect (mem_fun(*this, &Editor::canvas_horizontally_scrolled));
353 vertical_adjustment.signal_value_changed().connect (mem_fun(*this, &Editor::tie_vertical_scrolling), true);
355 track_canvas.set_hadjustment (horizontal_adjustment);
356 track_canvas.set_vadjustment (vertical_adjustment);
357 time_canvas.set_hadjustment (horizontal_adjustment);
359 track_canvas.signal_map_event().connect (mem_fun (*this, &Editor::track_canvas_map_handler));
360 time_canvas.signal_map_event().connect (mem_fun (*this, &Editor::time_canvas_map_handler));
362 controls_layout.add (edit_controls_vbox);
363 controls_layout.set_name ("EditControlsBase");
364 controls_layout.add_events (Gdk::SCROLL_MASK);
365 controls_layout.signal_scroll_event().connect (mem_fun(*this, &Editor::control_layout_scroll), false);
367 controls_layout.add_events (Gdk::BUTTON_PRESS_MASK|Gdk::BUTTON_RELEASE_MASK|Gdk::ENTER_NOTIFY_MASK|Gdk::LEAVE_NOTIFY_MASK);
368 controls_layout.signal_button_release_event().connect (mem_fun(*this, &Editor::edit_controls_button_release));
369 controls_layout.signal_size_request().connect (mem_fun (*this, &Editor::controls_layout_size_request));
371 edit_vscrollbar.set_adjustment (vertical_adjustment);
372 edit_hscrollbar.set_adjustment (horizontal_adjustment);
374 edit_hscrollbar.signal_button_press_event().connect (mem_fun(*this, &Editor::hscrollbar_button_press), false);
375 edit_hscrollbar.signal_button_release_event().connect (mem_fun(*this, &Editor::hscrollbar_button_release), false);
376 edit_hscrollbar.signal_size_allocate().connect (mem_fun(*this, &Editor::hscrollbar_allocate));
378 edit_hscrollbar.set_name ("EditorHScrollbar");
383 edit_cursor_clock.ValueChanged.connect (mem_fun(*this, &Editor::edit_cursor_clock_changed));
385 time_canvas_vbox.pack_start (*_ruler_separator, false, false);
386 time_canvas_vbox.pack_start (*minsec_ruler, false, false);
387 time_canvas_vbox.pack_start (*smpte_ruler, false, false);
388 time_canvas_vbox.pack_start (*frames_ruler, false, false);
389 time_canvas_vbox.pack_start (*bbt_ruler, false, false);
390 time_canvas_vbox.pack_start (time_canvas, true, true);
391 time_canvas_vbox.set_size_request (-1, (int)(timebar_height * visible_timebars) + 2);
393 bbt_label.set_name ("EditorTimeButton");
394 bbt_label.set_size_request (-1, (int)timebar_height);
395 bbt_label.set_alignment (1.0, 0.5);
396 bbt_label.set_padding (5,0);
397 minsec_label.set_name ("EditorTimeButton");
398 minsec_label.set_size_request (-1, (int)timebar_height);
399 minsec_label.set_alignment (1.0, 0.5);
400 minsec_label.set_padding (5,0);
401 smpte_label.set_name ("EditorTimeButton");
402 smpte_label.set_size_request (-1, (int)timebar_height);
403 smpte_label.set_alignment (1.0, 0.5);
404 smpte_label.set_padding (5,0);
405 frame_label.set_name ("EditorTimeButton");
406 frame_label.set_size_request (-1, (int)timebar_height);
407 frame_label.set_alignment (1.0, 0.5);
408 frame_label.set_padding (5,0);
409 tempo_label.set_name ("EditorTimeButton");
410 tempo_label.set_size_request (-1, (int)timebar_height);
411 tempo_label.set_alignment (1.0, 0.5);
412 tempo_label.set_padding (5,0);
413 meter_label.set_name ("EditorTimeButton");
414 meter_label.set_size_request (-1, (int)timebar_height);
415 meter_label.set_alignment (1.0, 0.5);
416 meter_label.set_padding (5,0);
417 mark_label.set_name ("EditorTimeButton");
418 mark_label.set_size_request (-1, (int)timebar_height);
419 mark_label.set_alignment (1.0, 0.5);
420 mark_label.set_padding (5,0);
421 range_mark_label.set_name ("EditorTimeButton");
422 range_mark_label.set_size_request (-1, (int)timebar_height);
423 range_mark_label.set_alignment (1.0, 0.5);
424 range_mark_label.set_padding (5,0);
425 transport_mark_label.set_name ("EditorTimeButton");
426 transport_mark_label.set_size_request (-1, (int)timebar_height);
427 transport_mark_label.set_alignment (1.0, 0.5);
428 transport_mark_label.set_padding (5,0);
430 time_button_vbox.pack_start (minsec_label, false, false);
431 time_button_vbox.pack_start (smpte_label, false, false);
432 time_button_vbox.pack_start (frame_label, false, false);
433 time_button_vbox.pack_start (bbt_label, false, false);
434 time_button_vbox.pack_start (meter_label, false, false);
435 time_button_vbox.pack_start (tempo_label, false, false);
436 time_button_vbox.pack_start (mark_label, false, false);
438 time_button_event_box.add (time_button_vbox);
440 time_button_event_box.set_events (Gdk::BUTTON_PRESS_MASK|Gdk::BUTTON_RELEASE_MASK);
441 time_button_event_box.set_name ("TimebarLabelBase");
442 time_button_event_box.signal_button_release_event().connect (mem_fun(*this, &Editor::ruler_label_button_release));
444 time_button_frame.add(time_button_event_box);
445 time_button_frame.property_shadow_type() = Gtk::SHADOW_OUT;
447 /* these enable us to have a dedicated window (for cursor setting, etc.)
448 for the canvas areas.
451 track_canvas_event_box.add (track_canvas);
453 time_canvas_event_box.add (time_canvas_vbox);
454 time_canvas_event_box.set_events (Gdk::BUTTON_PRESS_MASK|Gdk::BUTTON_RELEASE_MASK|Gdk::POINTER_MOTION_MASK);
456 edit_packer.set_col_spacings (0);
457 edit_packer.set_row_spacings (0);
458 edit_packer.set_homogeneous (false);
459 edit_packer.set_border_width (0);
460 edit_packer.set_name ("EditorWindow");
462 edit_packer.attach (edit_vscrollbar, 0, 1, 1, 3, FILL, FILL|EXPAND, 0, 0);
464 edit_packer.attach (time_button_frame, 0, 2, 0, 1, FILL, FILL, 0, 0);
465 edit_packer.attach (time_canvas_event_box, 2, 3, 0, 1, FILL|EXPAND, FILL, 0, 0);
467 edit_packer.attach (controls_layout, 1, 2, 1, 2, FILL, FILL|EXPAND, 0, 0);
468 edit_packer.attach (track_canvas_event_box, 2, 3, 1, 2, FILL|EXPAND, FILL|EXPAND, 0, 0);
470 edit_packer.attach (zoom_box, 1, 2, 2, 3, FILL, FILL, 0, 0);
471 edit_packer.attach (edit_hscrollbar, 2, 3, 2, 3, FILL|EXPAND, FILL, 0, 0);
473 bottom_hbox.set_border_width (2);
474 bottom_hbox.set_spacing (3);
476 route_display_model = ListStore::create(route_display_columns);
477 route_list_display.set_model (route_display_model);
478 route_list_display.append_column (_("Show"), route_display_columns.visible);
479 route_list_display.append_column (_("Name"), route_display_columns.text);
480 route_list_display.get_column (0)->set_data (X_("colnum"), GUINT_TO_POINTER(0));
481 route_list_display.get_column (1)->set_data (X_("colnum"), GUINT_TO_POINTER(1));
482 route_list_display.set_headers_visible (true);
483 route_list_display.set_name ("TrackListDisplay");
484 route_list_display.get_selection()->set_mode (SELECTION_NONE);
485 route_list_display.set_reorderable (true);
486 route_list_display.set_size_request (100,-1);
488 CellRendererToggle* route_list_visible_cell = dynamic_cast<CellRendererToggle*>(route_list_display.get_column_cell_renderer (0));
489 route_list_visible_cell->property_activatable() = true;
490 route_list_visible_cell->property_radio() = false;
492 route_display_model->signal_row_deleted().connect (mem_fun (*this, &Editor::route_list_delete));
493 route_display_model->signal_row_changed().connect (mem_fun (*this, &Editor::route_list_change));
494 route_display_model->signal_rows_reordered().connect (mem_fun (*this, &Editor::track_list_reorder));
496 route_list_display.signal_button_press_event().connect (mem_fun (*this, &Editor::route_list_display_button_press), false);
498 route_list_scroller.add (route_list_display);
499 route_list_scroller.set_policy (POLICY_NEVER, POLICY_AUTOMATIC);
501 group_model = ListStore::create(group_columns);
502 edit_group_display.set_model (group_model);
503 edit_group_display.append_column (_("Name"), group_columns.text);
504 edit_group_display.append_column (_("Active"), group_columns.is_active);
505 edit_group_display.append_column (_("Show"), group_columns.is_visible);
506 edit_group_display.get_column (0)->set_data (X_("colnum"), GUINT_TO_POINTER(0));
507 edit_group_display.get_column (1)->set_data (X_("colnum"), GUINT_TO_POINTER(1));
508 edit_group_display.get_column (2)->set_data (X_("colnum"), GUINT_TO_POINTER(2));
509 edit_group_display.get_column (0)->set_expand (true);
510 edit_group_display.get_column (1)->set_expand (false);
511 edit_group_display.get_column (2)->set_expand (false);
512 edit_group_display.set_headers_visible (true);
514 /* name is directly editable */
516 CellRendererText* name_cell = dynamic_cast<CellRendererText*>(edit_group_display.get_column_cell_renderer (0));
517 name_cell->property_editable() = true;
518 name_cell->signal_edited().connect (mem_fun (*this, &Editor::edit_group_name_edit));
520 /* use checkbox for the active + visible columns */
522 CellRendererToggle* active_cell = dynamic_cast<CellRendererToggle*>(edit_group_display.get_column_cell_renderer (1));
523 active_cell->property_activatable() = true;
524 active_cell->property_radio() = false;
526 active_cell = dynamic_cast<CellRendererToggle*>(edit_group_display.get_column_cell_renderer (1));
527 active_cell->property_activatable() = true;
528 active_cell->property_radio() = false;
530 group_model->signal_row_changed().connect (mem_fun (*this, &Editor::edit_group_row_change));
532 edit_group_display.set_name ("EditGroupList");
533 edit_group_display.get_selection()->set_mode (SELECTION_SINGLE);
534 edit_group_display.set_headers_visible (true);
535 edit_group_display.set_reorderable (false);
536 edit_group_display.set_rules_hint (true);
537 edit_group_display.set_size_request (75, -1);
539 edit_group_display_scroller.add (edit_group_display);
540 edit_group_display_scroller.set_policy (POLICY_AUTOMATIC, POLICY_AUTOMATIC);
542 edit_group_display.signal_button_press_event().connect (mem_fun(*this, &Editor::edit_group_list_button_press_event), false);
544 VBox* edit_group_display_packer = manage (new VBox());
545 HBox* edit_group_display_button_box = manage (new HBox());
546 edit_group_display_button_box->set_homogeneous (true);
548 Button* edit_group_add_button = manage (new Button ());
549 Button* edit_group_remove_button = manage (new Button ());
553 w = manage (new Image (Stock::ADD, ICON_SIZE_BUTTON));
555 edit_group_add_button->add (*w);
557 w = manage (new Image (Stock::REMOVE, ICON_SIZE_BUTTON));
559 edit_group_remove_button->add (*w);
561 edit_group_add_button->signal_clicked().connect (mem_fun (*this, &Editor::new_edit_group));
562 edit_group_remove_button->signal_clicked().connect (mem_fun (*this, &Editor::remove_selected_edit_group));
564 edit_group_display_button_box->pack_start (*edit_group_add_button);
565 edit_group_display_button_box->pack_start (*edit_group_remove_button);
567 edit_group_display_packer->pack_start (edit_group_display_scroller, true, true);
568 edit_group_display_packer->pack_start (*edit_group_display_button_box, false, false);
570 region_list_display.set_size_request (100, -1);
571 region_list_display.set_name ("RegionListDisplay");
573 region_list_model = TreeStore::create (region_list_columns);
574 region_list_model->set_sort_func (0, mem_fun (*this, &Editor::region_list_sorter));
575 region_list_model->set_sort_column (0, SORT_ASCENDING);
577 region_list_display.set_model (region_list_model);
578 region_list_display.append_column (_("Regions"), region_list_columns.name);
579 region_list_display.set_headers_visible (false);
581 region_list_display.get_selection()->set_select_function (mem_fun (*this, &Editor::region_list_selection_filter));
583 TreeViewColumn* tv_col = region_list_display.get_column(0);
584 CellRendererText* renderer = dynamic_cast<CellRendererText*>(region_list_display.get_column_cell_renderer (0));
585 tv_col->add_attribute(renderer->property_text(), region_list_columns.name);
586 tv_col->add_attribute(renderer->property_foreground_gdk(), region_list_columns.color_);
588 region_list_display.get_selection()->set_mode (SELECTION_MULTIPLE);
589 region_list_display.add_object_drag (region_list_columns.region.index(), "regions");
591 /* setup DnD handling */
593 list<TargetEntry> region_list_target_table;
595 region_list_target_table.push_back (TargetEntry ("text/plain"));
596 region_list_target_table.push_back (TargetEntry ("text/uri-list"));
597 region_list_target_table.push_back (TargetEntry ("application/x-rootwin-drop"));
599 region_list_display.add_drop_targets (region_list_target_table);
600 region_list_display.signal_drag_data_received().connect (mem_fun(*this, &Editor::region_list_display_drag_data_received));
602 region_list_scroller.add (region_list_display);
603 region_list_scroller.set_policy (POLICY_NEVER, POLICY_AUTOMATIC);
605 region_list_display.signal_key_press_event().connect (mem_fun(*this, &Editor::region_list_display_key_press));
606 region_list_display.signal_key_release_event().connect (mem_fun(*this, &Editor::region_list_display_key_release));
607 region_list_display.signal_button_press_event().connect (mem_fun(*this, &Editor::region_list_display_button_press), false);
608 region_list_display.signal_button_release_event().connect (mem_fun(*this, &Editor::region_list_display_button_release));
609 region_list_display.get_selection()->signal_changed().connect (mem_fun(*this, &Editor::region_list_selection_changed));
610 // region_list_display.signal_popup_menu().connect (bind (mem_fun (*this, &Editor::show_region_list_display_context_menu), 1, 0));
612 named_selection_scroller.add (named_selection_display);
613 named_selection_scroller.set_policy (POLICY_NEVER, POLICY_AUTOMATIC);
615 named_selection_model = TreeStore::create (named_selection_columns);
616 named_selection_display.set_model (named_selection_model);
617 named_selection_display.append_column (_("Chunks"), named_selection_columns.text);
618 named_selection_display.set_headers_visible (false);
619 named_selection_display.set_size_request (100, -1);
620 named_selection_display.set_name ("NamedSelectionDisplay");
622 named_selection_display.get_selection()->set_mode (SELECTION_SINGLE);
623 named_selection_display.set_size_request (100, -1);
624 named_selection_display.signal_button_release_event().connect (mem_fun(*this, &Editor::named_selection_display_button_release), false);
625 named_selection_display.signal_key_release_event().connect (mem_fun(*this, &Editor::named_selection_display_key_release), false);
626 named_selection_display.get_selection()->signal_changed().connect (mem_fun (*this, &Editor::named_selection_display_selection_changed));
630 snapshot_display_model = ListStore::create (snapshot_display_columns);
631 snapshot_display.set_model (snapshot_display_model);
632 snapshot_display.append_column (X_("snapshot"), snapshot_display_columns.visible_name);
633 snapshot_display.set_name ("SnapshotDisplay");
634 snapshot_display.set_size_request (75, -1);
635 snapshot_display.set_headers_visible (false);
636 snapshot_display.set_reorderable (false);
637 snapshot_display_scroller.add (snapshot_display);
638 snapshot_display_scroller.set_policy (Gtk::POLICY_NEVER, Gtk::POLICY_AUTOMATIC);
640 snapshot_display.get_selection()->signal_changed().connect (mem_fun(*this, &Editor::snapshot_display_selection_changed));
641 snapshot_display.signal_button_press_event().connect (mem_fun (*this, &Editor::snapshot_display_button_press), false);
645 nlabel = manage (new Label (_("Regions")));
646 nlabel->set_angle (-90);
647 the_notebook.append_page (region_list_scroller, *nlabel);
648 nlabel = manage (new Label (_("Tracks/Busses")));
649 nlabel->set_angle (-90);
650 the_notebook.append_page (route_list_scroller, *nlabel);
651 nlabel = manage (new Label (_("Snapshots")));
652 nlabel->set_angle (-90);
653 the_notebook.append_page (snapshot_display_scroller, *nlabel);
654 nlabel = manage (new Label (_("Edit Groups")));
655 nlabel->set_angle (-90);
656 the_notebook.append_page (*edit_group_display_packer, *nlabel);
657 nlabel = manage (new Label (_("Chunks")));
658 nlabel->set_angle (-90);
659 the_notebook.append_page (named_selection_scroller, *nlabel);
661 the_notebook.set_show_tabs (true);
662 the_notebook.set_scrollable (true);
663 the_notebook.popup_enable ();
664 the_notebook.set_tab_pos (Gtk::POS_RIGHT);
666 post_maximal_editor_width = 0;
667 post_maximal_pane_position = 0;
668 edit_pane.pack1 (edit_packer, true, true);
669 edit_pane.pack2 (the_notebook, false, true);
671 edit_pane.signal_size_allocate().connect (bind (mem_fun(*this, &Editor::pane_allocation_handler), static_cast<Paned*> (&edit_pane)));
673 top_hbox.pack_start (toolbar_frame, true, true);
675 HBox *hbox = manage (new HBox);
676 hbox->pack_start (edit_pane, true, true);
678 global_vpacker.pack_start (top_hbox, false, false);
679 global_vpacker.pack_start (*hbox, true, true);
681 global_hpacker.pack_start (global_vpacker, true, true);
683 set_name ("EditorWindow");
684 add_accel_group (ActionManager::ui_manager->get_accel_group());
686 status_bar_hpacker.show ();
688 vpacker.pack_end (status_bar_hpacker, false, false);
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));
757 Route::SyncOrderKeys.connect (mem_fun (*this, &Editor::sync_order_keys));
765 /* <CMT Additions> */
766 if(image_socket_listener)
768 if(image_socket_listener->is_connected())
770 image_socket_listener->close_connection() ;
773 delete image_socket_listener ;
774 image_socket_listener = 0 ;
776 /* </CMT Additions> */
780 Editor::add_toplevel_controls (Container& cont)
782 vpacker.pack_start (cont, false, false);
787 Editor::catch_vanishing_regionview (RegionView *rv)
789 /* note: the selection will take care of the vanishing
790 audioregionview by itself.
793 if (clicked_regionview == rv) {
794 clicked_regionview = 0;
797 if (entered_regionview == rv) {
798 set_entered_regionview (0);
803 Editor::set_entered_regionview (RegionView* rv)
805 if (rv == entered_regionview) {
809 if (entered_regionview) {
810 entered_regionview->exited ();
813 if ((entered_regionview = rv) != 0) {
814 entered_regionview->entered ();
819 Editor::set_entered_track (TimeAxisView* tav)
822 entered_track->exited ();
825 if ((entered_track = tav) != 0) {
826 entered_track->entered ();
831 Editor::show_window ()
836 /* now reset all audio_time_axis heights, because widgets might need
842 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
843 tv = (static_cast<TimeAxisView*>(*i));
849 Editor::tie_vertical_scrolling ()
851 double y1 = vertical_adjustment.get_value();
853 playhead_cursor->set_y_axis (y1);
854 edit_cursor->set_y_axis (y1);
856 controls_layout.get_vadjustment()->set_value (y1);
859 /* the way idle updates and immediate window flushing work on GTK-Quartz
860 requires that we force an immediate redraw right here. The controls
861 layout will do the same all by itself, as does the canvas widget, but
862 most of the time, the canvas itself hasn't updated itself because its
863 idle handler hasn't run. consequently, the call that its layout makes
864 to gdk_window_process_updates() finds nothing to do. here, we force
865 the update to happen, then request a flush of the new window state.
867 track_canvas.update_now ();
868 gdk_window_process_updates (GTK_LAYOUT(track_canvas.gobj())->bin_window, true);
873 Editor::instant_save ()
875 if (!constructed || !ARDOUR_UI::instance()->session_loaded) {
880 session->add_instant_xml(get_state(), session->path());
882 Config->add_instant_xml(get_state(), get_user_ardour_path());
887 Editor::edit_cursor_clock_changed()
889 if (edit_cursor->current_frame != edit_cursor_clock.current_time()) {
890 edit_cursor->set_position (edit_cursor_clock.current_time());
896 Editor::zoom_adjustment_changed ()
902 double fpu = zoom_range_clock.current_duration() / canvas_width;
906 zoom_range_clock.set ((nframes_t) floor (fpu * canvas_width));
907 } else if (fpu > session->current_end_frame() / canvas_width) {
908 fpu = session->current_end_frame() / canvas_width;
909 zoom_range_clock.set ((nframes_t) floor (fpu * canvas_width));
916 Editor::control_scroll (float fraction)
918 ENSURE_GUI_THREAD(bind (mem_fun (*this, &Editor::control_scroll), fraction));
924 double step = fraction * current_page_frames();
927 _control_scroll_target is an optional<T>
929 it acts like a pointer to an nframes_t, with
930 a operator conversion to boolean to check
931 that it has a value could possibly use
932 playhead_cursor->current_frame to store the
933 value and a boolean in the class to know
934 when it's out of date
937 if (!_control_scroll_target) {
938 _control_scroll_target = session->transport_frame();
939 _dragging_playhead = true;
942 if ((fraction < 0.0f) && (*_control_scroll_target < (nframes_t) fabs(step))) {
943 *_control_scroll_target = 0;
944 } else if ((fraction > 0.0f) && (max_frames - *_control_scroll_target < step)) {
945 *_control_scroll_target = max_frames - (current_page_frames()*2); // allow room for slop in where the PH is on the screen
947 *_control_scroll_target += (nframes_t) floor (step);
950 /* move visuals, we'll catch up with it later */
952 playhead_cursor->set_position (*_control_scroll_target);
953 UpdateAllTransportClocks (*_control_scroll_target);
955 if (*_control_scroll_target > (current_page_frames() / 2)) {
956 /* try to center PH in window */
957 reset_x_origin (*_control_scroll_target - (current_page_frames()/2));
963 Now we do a timeout to actually bring the session to the right place
964 according to the playhead. This is to avoid reading disk buffers on every
965 call to control_scroll, which is driven by ScrollTimeline and therefore
966 probably by a control surface wheel which can generate lots of events.
968 /* cancel the existing timeout */
970 control_scroll_connection.disconnect ();
972 /* add the next timeout */
974 control_scroll_connection = Glib::signal_timeout().connect (bind (mem_fun (*this, &Editor::deferred_control_scroll), *_control_scroll_target), 250);
978 Editor::deferred_control_scroll (nframes_t target)
980 session->request_locate (*_control_scroll_target, session->transport_rolling());
981 // reset for next stream
982 _control_scroll_target = boost::none;
983 _dragging_playhead = false;
988 Editor::on_realize ()
990 Window::on_realize ();
995 Editor::start_scrolling ()
997 scroll_connection = ARDOUR_UI::instance()->SuperRapidScreenUpdate.connect
998 (mem_fun(*this, &Editor::update_current_screen));
1002 Editor::stop_scrolling ()
1004 scroll_connection.disconnect ();
1008 Editor::map_position_change (nframes_t frame)
1010 ENSURE_GUI_THREAD (bind (mem_fun(*this, &Editor::map_position_change), frame));
1012 if (session == 0 || !_follow_playhead) {
1016 center_screen (frame);
1017 playhead_cursor->set_position (frame);
1021 Editor::center_screen (nframes_t frame)
1023 double page = canvas_width * frames_per_unit;
1025 /* if we're off the page, then scroll.
1028 if (frame < leftmost_frame || frame >= leftmost_frame + page) {
1029 center_screen_internal (frame, page);
1034 Editor::center_screen_internal (nframes_t frame, float page)
1039 frame -= (nframes_t) page;
1044 reset_x_origin (frame);
1048 Editor::handle_new_duration ()
1050 ENSURE_GUI_THREAD (mem_fun (*this, &Editor::handle_new_duration));
1052 nframes_t new_end = session->get_maximum_extent() + (nframes_t) floorf (current_page_frames() * 0.10f);
1054 if (new_end > last_canvas_frame) {
1055 last_canvas_frame = new_end;
1056 horizontal_adjustment.set_upper (last_canvas_frame / frames_per_unit);
1057 reset_scrolling_region ();
1060 horizontal_adjustment.set_value (leftmost_frame/frames_per_unit);
1064 Editor::update_title_s (const string & snap_name)
1066 ENSURE_GUI_THREAD(bind (mem_fun(*this, &Editor::update_title_s), snap_name));
1072 Editor::update_title ()
1074 ENSURE_GUI_THREAD (mem_fun(*this, &Editor::update_title));
1077 bool dirty = session->dirty();
1079 string session_name;
1081 if (session->snap_name() != session->name()) {
1082 session_name = session->snap_name();
1084 session_name = session->name();
1088 session_name = "*" + session_name;
1091 WindowTitle title(session_name);
1092 title += Glib::get_application_name();
1093 set_title (title.get_string());
1098 Editor::connect_to_session (Session *t)
1102 XMLNode* node = ARDOUR_UI::instance()->editor_settings();
1105 /* catch up with the playhead */
1107 session->request_locate (playhead_cursor->current_frame);
1109 if (first_action_message) {
1110 first_action_message->hide();
1115 session->GoingAway.connect (mem_fun(*this, &Editor::session_going_away));
1116 session->history().Changed.connect (mem_fun (*this, &Editor::history_changed));
1118 /* These signals can all be emitted by a non-GUI thread. Therefore the
1119 handlers for them must not attempt to directly interact with the GUI,
1120 but use Gtkmm2ext::UI::instance()->call_slot();
1123 session_connections.push_back (session->TransportStateChange.connect (mem_fun(*this, &Editor::map_transport_state)));
1124 session_connections.push_back (session->PositionChanged.connect (mem_fun(*this, &Editor::map_position_change)));
1125 session_connections.push_back (session->RouteAdded.connect (mem_fun(*this, &Editor::handle_new_route)));
1126 session_connections.push_back (session->AudioRegionAdded.connect (mem_fun(*this, &Editor::handle_new_audio_region)));
1127 session_connections.push_back (session->AudioRegionRemoved.connect (mem_fun(*this, &Editor::handle_audio_region_removed)));
1128 session_connections.push_back (session->DurationChanged.connect (mem_fun(*this, &Editor::handle_new_duration)));
1129 session_connections.push_back (session->edit_group_added.connect (mem_fun(*this, &Editor::add_edit_group)));
1130 session_connections.push_back (session->edit_group_removed.connect (mem_fun(*this, &Editor::edit_groups_changed)));
1131 session_connections.push_back (session->NamedSelectionAdded.connect (mem_fun(*this, &Editor::handle_new_named_selection)));
1132 session_connections.push_back (session->NamedSelectionRemoved.connect (mem_fun(*this, &Editor::handle_new_named_selection)));
1133 session_connections.push_back (session->DirtyChanged.connect (mem_fun(*this, &Editor::update_title)));
1134 session_connections.push_back (session->StateSaved.connect (mem_fun(*this, &Editor::update_title_s)));
1135 session_connections.push_back (session->AskAboutPlaylistDeletion.connect (mem_fun(*this, &Editor::playlist_deletion_dialog)));
1136 session_connections.push_back (session->RegionHiddenChange.connect (mem_fun(*this, &Editor::region_hidden)));
1138 session_connections.push_back (session->SMPTEOffsetChanged.connect (mem_fun(*this, &Editor::update_just_smpte)));
1140 session_connections.push_back (session->tempo_map().StateChanged.connect (mem_fun(*this, &Editor::tempo_map_changed)));
1142 edit_groups_changed ();
1144 edit_cursor_clock.set_session (session);
1145 zoom_range_clock.set_session (session);
1146 _playlist_selector->set_session (session);
1147 nudge_clock.set_session (session);
1150 if (analysis_window != 0)
1151 analysis_window->set_session (session);
1154 Location* loc = session->locations()->auto_loop_location();
1156 loc = new Location (0, session->current_end_frame(), _("Loop"),(Location::Flags) (Location::IsAutoLoop | Location::IsHidden));
1157 if (loc->start() == loc->end()) {
1158 loc->set_end (loc->start() + 1);
1160 session->locations()->add (loc, false);
1161 session->set_auto_loop_location (loc);
1164 loc->set_name (_("Loop"));
1167 loc = session->locations()->auto_punch_location();
1169 loc = new Location (0, session->current_end_frame(), _("Punch"), (Location::Flags) (Location::IsAutoPunch | Location::IsHidden));
1170 if (loc->start() == loc->end()) {
1171 loc->set_end (loc->start() + 1);
1173 session->locations()->add (loc, false);
1174 session->set_auto_punch_location (loc);
1177 loc->set_name (_("Punch"));
1180 Config->map_parameters (mem_fun (*this, &Editor::parameter_changed));
1182 session->StateSaved.connect (mem_fun(*this, &Editor::session_state_saved));
1184 refresh_location_display ();
1185 session->locations()->added.connect (mem_fun(*this, &Editor::add_new_location));
1186 session->locations()->removed.connect (mem_fun(*this, &Editor::location_gone));
1187 session->locations()->changed.connect (mem_fun(*this, &Editor::refresh_location_display));
1188 session->locations()->StateChanged.connect (mem_fun(*this, &Editor::refresh_location_display_s));
1189 session->locations()->end_location()->changed.connect (mem_fun(*this, &Editor::end_location_changed));
1192 sfbrowser->set_session (session);
1195 handle_new_duration ();
1197 redisplay_regions ();
1198 redisplay_named_selections ();
1199 redisplay_snapshots ();
1201 initial_route_list_display ();
1203 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
1204 (static_cast<TimeAxisView*>(*i))->set_samples_per_unit (frames_per_unit);
1207 restore_ruler_visibility ();
1208 //tempo_map_changed (Change (0));
1209 session->tempo_map().apply_with_metrics (*this, &Editor::draw_metric_marks);
1213 /* don't show master bus in a new session */
1215 if (ARDOUR_UI::instance()->session_is_new ()) {
1217 TreeModel::Children rows = route_display_model->children();
1218 TreeModel::Children::iterator i;
1220 no_route_list_redisplay = true;
1222 for (i = rows.begin(); i != rows.end(); ++i) {
1223 TimeAxisView *tv = (*i)[route_display_columns.tv];
1224 AudioTimeAxisView *atv;
1226 if ((atv = dynamic_cast<AudioTimeAxisView*>(tv)) != 0) {
1227 if (atv->route()->master()) {
1228 route_list_display.get_selection()->unselect (i);
1233 no_route_list_redisplay = false;
1234 redisplay_route_list ();
1237 /* register for undo history */
1239 session->register_with_memento_command_factory(_id, this);
1243 Editor::build_cursors ()
1245 using namespace Gdk;
1247 Gdk::Color mbg ("#000000" ); /* Black */
1248 Gdk::Color mfg ("#0000ff" ); /* Blue. */
1251 RefPtr<Bitmap> source, mask;
1252 source = Bitmap::create (mag_bits, mag_width, mag_height);
1253 mask = Bitmap::create (magmask_bits, mag_width, mag_height);
1254 zoom_cursor = new Gdk::Cursor (source, mask, mfg, mbg, mag_x_hot, mag_y_hot);
1257 Gdk::Color fbg ("#ffffff" );
1258 Gdk::Color ffg ("#000000" );
1261 RefPtr<Bitmap> source, mask;
1263 source = Bitmap::create (fader_cursor_bits, fader_cursor_width, fader_cursor_height);
1264 mask = Bitmap::create (fader_cursor_mask_bits, fader_cursor_width, fader_cursor_height);
1265 fader_cursor = new Gdk::Cursor (source, mask, ffg, fbg, fader_cursor_x_hot, fader_cursor_y_hot);
1269 RefPtr<Bitmap> source, mask;
1270 source = Bitmap::create (speaker_cursor_bits, speaker_cursor_width, speaker_cursor_height);
1271 mask = Bitmap::create (speaker_cursor_mask_bits, speaker_cursor_width, speaker_cursor_height);
1272 speaker_cursor = new Gdk::Cursor (source, mask, ffg, fbg, speaker_cursor_x_hot, speaker_cursor_y_hot);
1275 grabber_cursor = new Gdk::Cursor (HAND2);
1276 cross_hair_cursor = new Gdk::Cursor (CROSSHAIR);
1277 trimmer_cursor = new Gdk::Cursor (SB_H_DOUBLE_ARROW);
1278 selector_cursor = new Gdk::Cursor (XTERM);
1279 time_fx_cursor = new Gdk::Cursor (SIZING);
1280 wait_cursor = new Gdk::Cursor (WATCH);
1281 timebar_cursor = new Gdk::Cursor(LEFT_PTR);
1285 Editor::popup_fade_context_menu (int button, int32_t time, ArdourCanvas::Item* item, ItemType item_type)
1287 using namespace Menu_Helpers;
1288 AudioRegionView* arv = static_cast<AudioRegionView*> (item->get_data ("regionview"));
1291 fatal << _("programming error: fade in canvas item has no regionview data pointer!") << endmsg;
1295 MenuList& items (fade_context_menu.items());
1299 switch (item_type) {
1301 case FadeInHandleItem:
1302 if (arv->audio_region()->fade_in_active()) {
1303 items.push_back (MenuElem (_("Deactivate"), bind (mem_fun (*this, &Editor::set_fade_in_active), false)));
1305 items.push_back (MenuElem (_("Activate"), bind (mem_fun (*this, &Editor::set_fade_in_active), true)));
1308 items.push_back (SeparatorElem());
1310 if (Profile->get_sae()) {
1311 items.push_back (MenuElem (_("Linear"), bind (mem_fun (*this, &Editor::set_fade_in_shape), AudioRegion::Linear)));
1312 items.push_back (MenuElem (_("Slowest"), bind (mem_fun (*this, &Editor::set_fade_in_shape), AudioRegion::Fast)));
1314 items.push_back (MenuElem (_("Linear"), bind (mem_fun (*this, &Editor::set_fade_in_shape), AudioRegion::Linear)));
1315 items.push_back (MenuElem (_("Slowest"), bind (mem_fun (*this, &Editor::set_fade_in_shape), AudioRegion::Fast)));
1316 items.push_back (MenuElem (_("Slow"), bind (mem_fun (*this, &Editor::set_fade_in_shape), AudioRegion::LogB)));
1317 items.push_back (MenuElem (_("Fast"), bind (mem_fun (*this, &Editor::set_fade_in_shape), AudioRegion::LogA)));
1318 items.push_back (MenuElem (_("Fastest"), bind (mem_fun (*this, &Editor::set_fade_in_shape), AudioRegion::Slow)));
1323 case FadeOutHandleItem:
1324 if (arv->audio_region()->fade_out_active()) {
1325 items.push_back (MenuElem (_("Deactivate"), bind (mem_fun (*this, &Editor::set_fade_out_active), false)));
1327 items.push_back (MenuElem (_("Activate"), bind (mem_fun (*this, &Editor::set_fade_out_active), true)));
1330 items.push_back (SeparatorElem());
1332 if (Profile->get_sae()) {
1333 items.push_back (MenuElem (_("Linear"), bind (mem_fun (*this, &Editor::set_fade_out_shape), AudioRegion::Linear)));
1334 items.push_back (MenuElem (_("Slowest"), bind (mem_fun (*this, &Editor::set_fade_out_shape), AudioRegion::Slow)));
1336 items.push_back (MenuElem (_("Linear"), bind (mem_fun (*this, &Editor::set_fade_out_shape), AudioRegion::Linear)));
1337 items.push_back (MenuElem (_("Slowest"), bind (mem_fun (*this, &Editor::set_fade_out_shape), AudioRegion::Slow)));
1338 items.push_back (MenuElem (_("Slow"), bind (mem_fun (*this, &Editor::set_fade_out_shape), AudioRegion::LogA)));
1339 items.push_back (MenuElem (_("Fast"), bind (mem_fun (*this, &Editor::set_fade_out_shape), AudioRegion::LogB)));
1340 items.push_back (MenuElem (_("Fastest"), bind (mem_fun (*this, &Editor::set_fade_out_shape), AudioRegion::Fast)));
1345 fatal << _("programming error: ")
1346 << X_("non-fade canvas item passed to popup_fade_context_menu()")
1351 fade_context_menu.popup (button, time);
1355 Editor::popup_track_context_menu (int button, int32_t time, ItemType item_type, bool with_selection, nframes_t frame)
1357 using namespace Menu_Helpers;
1358 Menu* (Editor::*build_menu_function)(nframes_t);
1361 switch (item_type) {
1363 case RegionViewName:
1364 case RegionViewNameHighlight:
1365 if (with_selection) {
1366 build_menu_function = &Editor::build_track_selection_context_menu;
1368 build_menu_function = &Editor::build_track_region_context_menu;
1373 if (with_selection) {
1374 build_menu_function = &Editor::build_track_selection_context_menu;
1376 build_menu_function = &Editor::build_track_context_menu;
1380 case CrossfadeViewItem:
1381 build_menu_function = &Editor::build_track_crossfade_context_menu;
1385 if (clicked_audio_trackview->get_diskstream()) {
1386 build_menu_function = &Editor::build_track_context_menu;
1388 build_menu_function = &Editor::build_track_bus_context_menu;
1393 /* probably shouldn't happen but if it does, we don't care */
1397 menu = (this->*build_menu_function)(frame);
1398 menu->set_name ("ArdourContextMenu");
1400 /* now handle specific situations */
1402 switch (item_type) {
1404 case RegionViewName:
1405 case RegionViewNameHighlight:
1406 if (!with_selection) {
1407 if (region_edit_menu_split_item) {
1408 if (clicked_regionview && clicked_regionview->region()->covers (edit_cursor->current_frame)) {
1409 ActionManager::set_sensitive (ActionManager::edit_cursor_in_region_sensitive_actions, true);
1411 ActionManager::set_sensitive (ActionManager::edit_cursor_in_region_sensitive_actions, false);
1415 if (region_edit_menu_split_multichannel_item) {
1416 if (clicked_regionview && clicked_regionview->region().n_channels() > 1) {
1417 // GTK2FIX find the action, change its sensitivity
1418 // region_edit_menu_split_multichannel_item->set_sensitive (true);
1420 // GTK2FIX see above
1421 // region_edit_menu_split_multichannel_item->set_sensitive (false);
1430 case CrossfadeViewItem:
1437 /* probably shouldn't happen but if it does, we don't care */
1441 if (item_type != SelectionItem && clicked_audio_trackview && clicked_audio_trackview->audio_track()) {
1443 /* Bounce to disk */
1445 using namespace Menu_Helpers;
1446 MenuList& edit_items = menu->items();
1448 edit_items.push_back (SeparatorElem());
1450 switch (clicked_audio_trackview->audio_track()->freeze_state()) {
1451 case AudioTrack::NoFreeze:
1452 edit_items.push_back (MenuElem (_("Freeze"), mem_fun(*this, &Editor::freeze_route)));
1455 case AudioTrack::Frozen:
1456 edit_items.push_back (MenuElem (_("Unfreeze"), mem_fun(*this, &Editor::unfreeze_route)));
1459 case AudioTrack::UnFrozen:
1460 edit_items.push_back (MenuElem (_("Freeze"), mem_fun(*this, &Editor::freeze_route)));
1466 menu->popup (button, time);
1470 Editor::build_track_context_menu (nframes_t ignored)
1472 using namespace Menu_Helpers;
1474 MenuList& edit_items = track_context_menu.items();
1477 add_dstream_context_items (edit_items);
1478 return &track_context_menu;
1482 Editor::build_track_bus_context_menu (nframes_t ignored)
1484 using namespace Menu_Helpers;
1486 MenuList& edit_items = track_context_menu.items();
1489 add_bus_context_items (edit_items);
1490 return &track_context_menu;
1494 Editor::build_track_region_context_menu (nframes_t frame)
1496 using namespace Menu_Helpers;
1497 MenuList& edit_items = track_region_context_menu.items();
1500 AudioTimeAxisView* atv = dynamic_cast<AudioTimeAxisView*> (clicked_trackview);
1503 boost::shared_ptr<Diskstream> ds;
1504 boost::shared_ptr<Playlist> pl;
1506 if ((ds = atv->get_diskstream()) && ((pl = ds->playlist()))) {
1507 Playlist::RegionList* regions = pl->regions_at ((nframes_t) floor ( (double)frame * ds->speed()));
1508 for (Playlist::RegionList::iterator i = regions->begin(); i != regions->end(); ++i) {
1509 add_region_context_items (atv->audio_view(), (*i), edit_items);
1515 add_dstream_context_items (edit_items);
1517 return &track_region_context_menu;
1521 Editor::build_track_crossfade_context_menu (nframes_t frame)
1523 using namespace Menu_Helpers;
1524 MenuList& edit_items = track_crossfade_context_menu.items();
1525 edit_items.clear ();
1527 AudioTimeAxisView* atv = dynamic_cast<AudioTimeAxisView*> (clicked_trackview);
1530 boost::shared_ptr<Diskstream> ds;
1531 boost::shared_ptr<Playlist> pl;
1532 boost::shared_ptr<AudioPlaylist> apl;
1534 if ((ds = atv->get_diskstream()) && ((pl = ds->playlist()) != 0) && ((apl = boost::dynamic_pointer_cast<AudioPlaylist> (pl)) != 0)) {
1536 Playlist::RegionList* regions = pl->regions_at (frame);
1537 AudioPlaylist::Crossfades xfades;
1539 apl->crossfades_at (frame, xfades);
1541 bool many = xfades.size() > 1;
1543 for (AudioPlaylist::Crossfades::iterator i = xfades.begin(); i != xfades.end(); ++i) {
1544 add_crossfade_context_items (atv->audio_view(), (*i), edit_items, many);
1547 for (Playlist::RegionList::iterator i = regions->begin(); i != regions->end(); ++i) {
1548 add_region_context_items (atv->audio_view(), (*i), edit_items);
1555 add_dstream_context_items (edit_items);
1557 return &track_crossfade_context_menu;
1562 Editor::analyze_region_selection()
1564 if (analysis_window == 0) {
1565 analysis_window = new AnalysisWindow();
1568 analysis_window->set_session(session);
1570 analysis_window->show_all();
1573 analysis_window->set_regionmode();
1574 analysis_window->analyze();
1576 analysis_window->present();
1580 Editor::analyze_range_selection()
1582 if (analysis_window == 0) {
1583 analysis_window = new AnalysisWindow();
1586 analysis_window->set_session(session);
1588 analysis_window->show_all();
1591 analysis_window->set_rangemode();
1592 analysis_window->analyze();
1594 analysis_window->present();
1596 #endif /* FFT_ANALYSIS */
1601 Editor::build_track_selection_context_menu (nframes_t ignored)
1603 using namespace Menu_Helpers;
1604 MenuList& edit_items = track_selection_context_menu.items();
1605 edit_items.clear ();
1607 add_selection_context_items (edit_items);
1608 // edit_items.push_back (SeparatorElem());
1609 // add_dstream_context_items (edit_items);
1611 return &track_selection_context_menu;
1615 Editor::add_crossfade_context_items (AudioStreamView* view, boost::shared_ptr<Crossfade> xfade, Menu_Helpers::MenuList& edit_items, bool many)
1617 using namespace Menu_Helpers;
1618 Menu *xfade_menu = manage (new Menu);
1619 MenuList& items = xfade_menu->items();
1620 xfade_menu->set_name ("ArdourContextMenu");
1623 if (xfade->active()) {
1629 items.push_back (MenuElem (str, bind (mem_fun(*this, &Editor::toggle_xfade_active), boost::weak_ptr<Crossfade> (xfade))));
1630 items.push_back (MenuElem (_("Edit"), bind (mem_fun(*this, &Editor::edit_xfade), boost::weak_ptr<Crossfade> (xfade))));
1632 if (xfade->can_follow_overlap()) {
1634 if (xfade->following_overlap()) {
1635 str = _("Convert to short");
1637 str = _("Convert to full");
1640 items.push_back (MenuElem (str, bind (mem_fun(*this, &Editor::toggle_xfade_length), xfade)));
1644 str = xfade->out()->name();
1646 str += xfade->in()->name();
1648 str = _("Crossfade");
1651 edit_items.push_back (MenuElem (str, *xfade_menu));
1652 edit_items.push_back (SeparatorElem());
1656 Editor::xfade_edit_left_region ()
1658 if (clicked_crossfadeview) {
1659 clicked_crossfadeview->left_view.show_region_editor ();
1664 Editor::xfade_edit_right_region ()
1666 if (clicked_crossfadeview) {
1667 clicked_crossfadeview->right_view.show_region_editor ();
1672 Editor::add_region_context_items (AudioStreamView* sv, boost::shared_ptr<Region> region, Menu_Helpers::MenuList& edit_items)
1674 using namespace Menu_Helpers;
1675 Menu *region_menu = manage (new Menu);
1676 MenuList& items = region_menu->items();
1677 region_menu->set_name ("ArdourContextMenu");
1679 boost::shared_ptr<AudioRegion> ar;
1682 ar = boost::dynamic_pointer_cast<AudioRegion> (region);
1685 /* when this particular menu pops up, make the relevant region
1689 region_menu->signal_map_event().connect (bind (mem_fun(*this, &Editor::set_selected_regionview_from_map_event), sv, boost::weak_ptr<Region>(region)));
1691 items.push_back (MenuElem (_("Popup region editor"), mem_fun(*this, &Editor::edit_region)));
1692 items.push_back (MenuElem (_("Raise to top layer"), mem_fun(*this, &Editor::raise_region_to_top)));
1693 items.push_back (MenuElem (_("Lower to bottom layer"), mem_fun (*this, &Editor::lower_region_to_bottom)));
1694 items.push_back (SeparatorElem());
1695 items.push_back (MenuElem (_("Define sync point"), mem_fun(*this, &Editor::set_region_sync_from_edit_cursor)));
1696 items.push_back (MenuElem (_("Remove sync point"), mem_fun(*this, &Editor::remove_region_sync)));
1697 items.push_back (SeparatorElem());
1699 items.push_back (MenuElem (_("Audition"), mem_fun(*this, &Editor::audition_selected_region)));
1700 items.push_back (MenuElem (_("Export"), mem_fun(*this, &Editor::export_region)));
1701 items.push_back (MenuElem (_("Bounce"), mem_fun(*this, &Editor::bounce_region_selection)));
1704 items.push_back (MenuElem (_("Analyze region"), mem_fun(*this, &Editor::analyze_region_selection)));
1707 items.push_back (SeparatorElem());
1709 sigc::connection fooc;
1711 items.push_back (CheckMenuElem (_("Lock")));
1712 region_lock_item = static_cast<CheckMenuItem*>(&items.back());
1713 fooc = region_lock_item->signal_activate().connect (mem_fun(*this, &Editor::toggle_region_lock));
1714 if (region->locked()) {
1716 region_lock_item->set_active();
1719 items.push_back (CheckMenuElem (_("Mute")));
1720 region_mute_item = static_cast<CheckMenuItem*>(&items.back());
1721 fooc = region_mute_item->signal_activate().connect (mem_fun(*this, &Editor::toggle_region_mute));
1722 if (region->muted()) {
1724 region_mute_item->set_active();
1728 if (!Profile->get_sae()) {
1729 items.push_back (CheckMenuElem (_("Opaque")));
1730 region_opaque_item = static_cast<CheckMenuItem*>(&items.back());
1731 fooc = region_opaque_item->signal_activate().connect (mem_fun(*this, &Editor::toggle_region_opaque));
1732 if (region->opaque()) {
1734 region_opaque_item->set_active();
1739 items.push_back (CheckMenuElem (_("Original position"), mem_fun(*this, &Editor::naturalize)));
1740 if (region->at_natural_position()) {
1741 items.back().set_sensitive (false);
1744 items.push_back (SeparatorElem());
1748 RegionView* rv = sv->find_view (ar);
1749 AudioRegionView* arv = dynamic_cast<AudioRegionView*>(rv);
1751 if (!Profile->get_sae()) {
1752 items.push_back (MenuElem (_("Reset Envelope"), mem_fun(*this, &Editor::reset_region_gain_envelopes)));
1754 items.push_back (CheckMenuElem (_("Envelope Visible")));
1755 region_envelope_visible_item = static_cast<CheckMenuItem*> (&items.back());
1756 fooc = region_envelope_visible_item->signal_activate().connect (mem_fun(*this, &Editor::toggle_gain_envelope_visibility));
1757 if (arv->envelope_visible()) {
1759 region_envelope_visible_item->set_active (true);
1763 items.push_back (CheckMenuElem (_("Envelope Active")));
1764 region_envelope_active_item = static_cast<CheckMenuItem*> (&items.back());
1765 fooc = region_envelope_active_item->signal_activate().connect (mem_fun(*this, &Editor::toggle_gain_envelope_active));
1767 if (ar->envelope_active()) {
1769 region_envelope_active_item->set_active (true);
1773 items.push_back (SeparatorElem());
1776 if (ar->scale_amplitude() != 1.0f) {
1777 items.push_back (MenuElem (_("DeNormalize"), mem_fun(*this, &Editor::denormalize_region)));
1779 items.push_back (MenuElem (_("Normalize"), mem_fun(*this, &Editor::normalize_region)));
1783 items.push_back (MenuElem (_("Reverse"), mem_fun(*this, &Editor::reverse_region)));
1784 items.push_back (SeparatorElem());
1786 /* range related stuff */
1788 items.push_back (MenuElem (_("Add Range Markers"), mem_fun (*this, &Editor::add_location_from_audio_region)));
1789 items.push_back (MenuElem (_("Set Range Selection"), mem_fun (*this, &Editor::set_selection_from_audio_region)));
1790 items.push_back (SeparatorElem());
1794 Menu *nudge_menu = manage (new Menu());
1795 MenuList& nudge_items = nudge_menu->items();
1796 nudge_menu->set_name ("ArdourContextMenu");
1798 nudge_items.push_back (MenuElem (_("Nudge fwd"), (bind (mem_fun(*this, &Editor::nudge_forward), false))));
1799 nudge_items.push_back (MenuElem (_("Nudge bwd"), (bind (mem_fun(*this, &Editor::nudge_backward), false))));
1800 nudge_items.push_back (MenuElem (_("Nudge fwd by capture offset"), (mem_fun(*this, &Editor::nudge_forward_capture_offset))));
1801 nudge_items.push_back (MenuElem (_("Nudge bwd by capture offset"), (mem_fun(*this, &Editor::nudge_backward_capture_offset))));
1803 items.push_back (MenuElem (_("Nudge"), *nudge_menu));
1804 items.push_back (SeparatorElem());
1806 Menu *trim_menu = manage (new Menu);
1807 MenuList& trim_items = trim_menu->items();
1808 trim_menu->set_name ("ArdourContextMenu");
1810 trim_items.push_back (MenuElem (_("Start to edit cursor"), mem_fun(*this, &Editor::trim_region_from_edit_cursor)));
1811 trim_items.push_back (MenuElem (_("Edit cursor to end"), mem_fun(*this, &Editor::trim_region_to_edit_cursor)));
1813 items.push_back (MenuElem (_("Trim"), *trim_menu));
1814 items.push_back (SeparatorElem());
1816 items.push_back (MenuElem (_("Split"), (mem_fun(*this, &Editor::split_region))));
1817 region_edit_menu_split_item = &items.back();
1819 items.push_back (MenuElem (_("Make mono regions"), (mem_fun(*this, &Editor::split_multichannel_region))));
1820 region_edit_menu_split_multichannel_item = &items.back();
1822 items.push_back (MenuElem (_("Duplicate"), (bind (mem_fun(*this, &Editor::duplicate_dialog), true))));
1823 items.push_back (MenuElem (_("Fill Track"), (mem_fun(*this, &Editor::region_fill_track))));
1824 items.push_back (SeparatorElem());
1825 items.push_back (MenuElem (_("Remove"), mem_fun(*this, &Editor::remove_clicked_region)));
1827 /* OK, stick the region submenu at the top of the list, and then add
1831 /* we have to hack up the region name because "_" has a special
1832 meaning for menu titles.
1835 string::size_type pos = 0;
1836 string menu_item_name = region->name();
1838 while ((pos = menu_item_name.find ("_", pos)) != string::npos) {
1839 menu_item_name.replace (pos, 1, "__");
1843 edit_items.push_back (MenuElem (menu_item_name, *region_menu));
1844 edit_items.push_back (SeparatorElem());
1848 Editor::add_selection_context_items (Menu_Helpers::MenuList& items)
1850 using namespace Menu_Helpers;
1852 items.push_back (MenuElem (_("Play range"), mem_fun(*this, &Editor::play_selection)));
1853 items.push_back (MenuElem (_("Loop range"), bind (mem_fun(*this, &Editor::set_loop_from_selection), true)));
1856 items.push_back (SeparatorElem());
1857 items.push_back (MenuElem (_("Analyze range"), mem_fun(*this, &Editor::analyze_range_selection)));
1860 items.push_back (SeparatorElem());
1861 items.push_back (MenuElem (_("Extend Range to End of Region"), bind (mem_fun(*this, &Editor::extend_selection_to_end_of_region), false)));
1862 items.push_back (MenuElem (_("Extend Range to Start of Region"), bind (mem_fun(*this, &Editor::extend_selection_to_start_of_region), false)));
1864 items.push_back (SeparatorElem());
1865 items.push_back (MenuElem (_("Convert to region in-place"), mem_fun(*this, &Editor::separate_region_from_selection)));
1866 items.push_back (MenuElem (_("Convert to region in region list"), mem_fun(*this, &Editor::new_region_from_selection)));
1868 items.push_back (SeparatorElem());
1869 items.push_back (MenuElem (_("Select all in range"), mem_fun(*this, &Editor::select_all_selectables_using_time_selection)));
1871 items.push_back (SeparatorElem());
1872 items.push_back (MenuElem (_("Set loop from selection"), bind (mem_fun(*this, &Editor::set_loop_from_selection), false)));
1873 items.push_back (MenuElem (_("Set punch from selection"), mem_fun(*this, &Editor::set_punch_from_selection)));
1875 items.push_back (SeparatorElem());
1876 items.push_back (MenuElem (_("Add Range Markers"), mem_fun (*this, &Editor::add_location_from_selection)));
1877 items.push_back (SeparatorElem());
1878 items.push_back (MenuElem (_("Crop region to range"), mem_fun(*this, &Editor::crop_region_to_selection)));
1879 items.push_back (MenuElem (_("Fill range with region"), mem_fun(*this, &Editor::region_fill_selection)));
1880 items.push_back (MenuElem (_("Duplicate range"), bind (mem_fun(*this, &Editor::duplicate_dialog), false)));
1881 items.push_back (MenuElem (_("Create chunk from range"), mem_fun(*this, &Editor::create_named_selection)));
1882 items.push_back (SeparatorElem());
1883 items.push_back (MenuElem (_("Bounce range"), mem_fun(*this, &Editor::bounce_range_selection)));
1884 items.push_back (MenuElem (_("Export range"), mem_fun(*this, &Editor::export_selection)));
1888 Editor::add_dstream_context_items (Menu_Helpers::MenuList& edit_items)
1890 using namespace Menu_Helpers;
1894 Menu *play_menu = manage (new Menu);
1895 MenuList& play_items = play_menu->items();
1896 play_menu->set_name ("ArdourContextMenu");
1898 play_items.push_back (MenuElem (_("Play from edit cursor"), mem_fun(*this, &Editor::play_from_edit_cursor)));
1899 play_items.push_back (MenuElem (_("Play from start"), mem_fun(*this, &Editor::play_from_start)));
1900 play_items.push_back (MenuElem (_("Play region"), mem_fun(*this, &Editor::play_selected_region)));
1901 play_items.push_back (SeparatorElem());
1902 play_items.push_back (MenuElem (_("Loop Region"), mem_fun(*this, &Editor::loop_selected_region)));
1904 edit_items.push_back (MenuElem (_("Play"), *play_menu));
1908 Menu *select_menu = manage (new Menu);
1909 MenuList& select_items = select_menu->items();
1910 select_menu->set_name ("ArdourContextMenu");
1912 select_items.push_back (MenuElem (_("Select All in track"), bind (mem_fun(*this, &Editor::select_all_in_track), Selection::Set)));
1913 select_items.push_back (MenuElem (_("Select All"), bind (mem_fun(*this, &Editor::select_all), Selection::Set)));
1914 select_items.push_back (MenuElem (_("Invert selection in track"), mem_fun(*this, &Editor::invert_selection_in_track)));
1915 select_items.push_back (MenuElem (_("Invert selection"), mem_fun(*this, &Editor::invert_selection)));
1916 select_items.push_back (SeparatorElem());
1917 select_items.push_back (MenuElem (_("Set range to loop range"), mem_fun(*this, &Editor::set_selection_from_loop)));
1918 select_items.push_back (MenuElem (_("Set range to punch range"), mem_fun(*this, &Editor::set_selection_from_punch)));
1919 select_items.push_back (SeparatorElem());
1920 select_items.push_back (MenuElem (_("Select all after edit cursor"), bind (mem_fun(*this, &Editor::select_all_selectables_using_cursor), edit_cursor, true)));
1921 select_items.push_back (MenuElem (_("Select all before edit cursor"), bind (mem_fun(*this, &Editor::select_all_selectables_using_cursor), edit_cursor, false)));
1922 select_items.push_back (MenuElem (_("Select all after playhead"), bind (mem_fun(*this, &Editor::select_all_selectables_using_cursor), playhead_cursor, true)));
1923 select_items.push_back (MenuElem (_("Select all before playhead"), bind (mem_fun(*this, &Editor::select_all_selectables_using_cursor), playhead_cursor, false)));
1924 select_items.push_back (MenuElem (_("Select all between cursors"), bind (mem_fun(*this, &Editor::select_all_selectables_between_cursors), playhead_cursor, edit_cursor)));
1925 select_items.push_back (SeparatorElem());
1927 edit_items.push_back (MenuElem (_("Select"), *select_menu));
1931 Menu *cutnpaste_menu = manage (new Menu);
1932 MenuList& cutnpaste_items = cutnpaste_menu->items();
1933 cutnpaste_menu->set_name ("ArdourContextMenu");
1935 cutnpaste_items.push_back (MenuElem (_("Cut"), mem_fun(*this, &Editor::cut)));
1936 cutnpaste_items.push_back (MenuElem (_("Copy"), mem_fun(*this, &Editor::copy)));
1937 cutnpaste_items.push_back (MenuElem (_("Paste at edit cursor"), bind (mem_fun(*this, &Editor::paste), 1.0f)));
1938 cutnpaste_items.push_back (MenuElem (_("Paste at mouse"), mem_fun(*this, &Editor::mouse_paste)));
1940 cutnpaste_items.push_back (SeparatorElem());
1942 cutnpaste_items.push_back (MenuElem (_("Align"), bind (mem_fun(*this, &Editor::align), ARDOUR::SyncPoint)));
1943 cutnpaste_items.push_back (MenuElem (_("Align Relative"), bind (mem_fun(*this, &Editor::align_relative), ARDOUR::SyncPoint)));
1945 cutnpaste_items.push_back (SeparatorElem());
1947 cutnpaste_items.push_back (MenuElem (_("Insert chunk"), bind (mem_fun(*this, &Editor::paste_named_selection), 1.0f)));
1949 edit_items.push_back (MenuElem (_("Edit"), *cutnpaste_menu));
1951 /* Adding new material */
1953 edit_items.push_back (SeparatorElem());
1954 edit_items.push_back (MenuElem (_("Insert Selected Region"), bind (mem_fun(*this, &Editor::insert_region_list_selection), 1.0f)));
1955 edit_items.push_back (MenuElem (_("Insert Existing Audio"), bind (mem_fun(*this, &Editor::add_external_audio_action), ImportToTrack)));
1959 Menu *nudge_menu = manage (new Menu());
1960 MenuList& nudge_items = nudge_menu->items();
1961 nudge_menu->set_name ("ArdourContextMenu");
1963 edit_items.push_back (SeparatorElem());
1964 nudge_items.push_back (MenuElem (_("Nudge entire track fwd"), (bind (mem_fun(*this, &Editor::nudge_track), false, true))));
1965 nudge_items.push_back (MenuElem (_("Nudge track after edit cursor fwd"), (bind (mem_fun(*this, &Editor::nudge_track), true, true))));
1966 nudge_items.push_back (MenuElem (_("Nudge entire track bwd"), (bind (mem_fun(*this, &Editor::nudge_track), false, false))));
1967 nudge_items.push_back (MenuElem (_("Nudge track after edit cursor bwd"), (bind (mem_fun(*this, &Editor::nudge_track), true, false))));
1969 edit_items.push_back (MenuElem (_("Nudge"), *nudge_menu));
1973 Editor::add_bus_context_items (Menu_Helpers::MenuList& edit_items)
1975 using namespace Menu_Helpers;
1979 Menu *play_menu = manage (new Menu);
1980 MenuList& play_items = play_menu->items();
1981 play_menu->set_name ("ArdourContextMenu");
1983 play_items.push_back (MenuElem (_("Play from edit cursor"), mem_fun(*this, &Editor::play_from_edit_cursor)));
1984 play_items.push_back (MenuElem (_("Play from start"), mem_fun(*this, &Editor::play_from_start)));
1985 edit_items.push_back (MenuElem (_("Play"), *play_menu));
1989 Menu *select_menu = manage (new Menu);
1990 MenuList& select_items = select_menu->items();
1991 select_menu->set_name ("ArdourContextMenu");
1993 select_items.push_back (MenuElem (_("Select All in track"), bind (mem_fun(*this, &Editor::select_all_in_track), Selection::Set)));
1994 select_items.push_back (MenuElem (_("Select All"), bind (mem_fun(*this, &Editor::select_all), Selection::Set)));
1995 select_items.push_back (MenuElem (_("Invert selection in track"), mem_fun(*this, &Editor::invert_selection_in_track)));
1996 select_items.push_back (MenuElem (_("Invert selection"), mem_fun(*this, &Editor::invert_selection)));
1997 select_items.push_back (SeparatorElem());
1998 select_items.push_back (MenuElem (_("Select all after edit cursor"), bind (mem_fun(*this, &Editor::select_all_selectables_using_cursor), edit_cursor, true)));
1999 select_items.push_back (MenuElem (_("Select all before edit cursor"), bind (mem_fun(*this, &Editor::select_all_selectables_using_cursor), edit_cursor, false)));
2000 select_items.push_back (MenuElem (_("Select all after playhead"), bind (mem_fun(*this, &Editor::select_all_selectables_using_cursor), playhead_cursor, true)));
2001 select_items.push_back (MenuElem (_("Select all before playhead"), bind (mem_fun(*this, &Editor::select_all_selectables_using_cursor), playhead_cursor, false)));
2003 edit_items.push_back (MenuElem (_("Select"), *select_menu));
2007 Menu *cutnpaste_menu = manage (new Menu);
2008 MenuList& cutnpaste_items = cutnpaste_menu->items();
2009 cutnpaste_menu->set_name ("ArdourContextMenu");
2011 cutnpaste_items.push_back (MenuElem (_("Cut"), mem_fun(*this, &Editor::cut)));
2012 cutnpaste_items.push_back (MenuElem (_("Copy"), mem_fun(*this, &Editor::copy)));
2013 cutnpaste_items.push_back (MenuElem (_("Paste"), bind (mem_fun(*this, &Editor::paste), 1.0f)));
2015 Menu *nudge_menu = manage (new Menu());
2016 MenuList& nudge_items = nudge_menu->items();
2017 nudge_menu->set_name ("ArdourContextMenu");
2019 edit_items.push_back (SeparatorElem());
2020 nudge_items.push_back (MenuElem (_("Nudge entire track fwd"), (bind (mem_fun(*this, &Editor::nudge_track), false, true))));
2021 nudge_items.push_back (MenuElem (_("Nudge track after edit cursor fwd"), (bind (mem_fun(*this, &Editor::nudge_track), true, true))));
2022 nudge_items.push_back (MenuElem (_("Nudge entire track bwd"), (bind (mem_fun(*this, &Editor::nudge_track), false, false))));
2023 nudge_items.push_back (MenuElem (_("Nudge track after edit cursor bwd"), (bind (mem_fun(*this, &Editor::nudge_track), true, false))));
2025 edit_items.push_back (MenuElem (_("Nudge"), *nudge_menu));
2028 /* CURSOR SETTING AND MARKS AND STUFF */
2031 Editor::set_snap_to (SnapType st)
2034 string str = snap_type_strings[(int) st];
2036 if (str != snap_type_selector.get_active_text()) {
2037 snap_type_selector.set_active_text (str);
2042 switch (snap_type) {
2043 case SnapToAThirtysecondBeat:
2044 case SnapToASixteenthBeat:
2045 case SnapToAEighthBeat:
2046 case SnapToAQuarterBeat:
2047 case SnapToAThirdBeat:
2048 update_tempo_based_rulers ();
2056 Editor::set_snap_mode (SnapMode mode)
2059 string str = snap_mode_strings[(int)mode];
2061 if (str != snap_mode_selector.get_active_text ()) {
2062 snap_mode_selector.set_active_text (str);
2069 Editor::set_state (const XMLNode& node)
2071 const XMLProperty* prop;
2073 int x, y, xoff, yoff;
2076 if ((prop = node.property ("id")) != 0) {
2077 _id = prop->value ();
2080 if ((geometry = find_named_node (node, "geometry")) == 0) {
2082 g.base_width = default_width;
2083 g.base_height = default_height;
2091 g.base_width = atoi(geometry->property("x_size")->value());
2092 g.base_height = atoi(geometry->property("y_size")->value());
2093 x = atoi(geometry->property("x_pos")->value());
2094 y = atoi(geometry->property("y_pos")->value());
2095 xoff = atoi(geometry->property("x_off")->value());
2096 yoff = atoi(geometry->property("y_off")->value());
2099 set_default_size (g.base_width, g.base_height);
2102 if (session && (prop = node.property ("playhead"))) {
2103 nframes_t pos = atol (prop->value().c_str());
2104 playhead_cursor->set_position (pos);
2106 playhead_cursor->set_position (0);
2108 /* reset_x_origin() doesn't work right here, since the old
2109 position may be zero already, and it does nothing in such
2114 horizontal_adjustment.set_value (0);
2117 if (session && (prop = node.property ("edit-cursor"))) {
2118 nframes_t pos = atol (prop->value().c_str());
2119 edit_cursor->set_position (pos);
2121 edit_cursor->set_position (0);
2124 if ((prop = node.property ("mixer-width"))) {
2125 editor_mixer_strip_width = Width (string_2_enum (prop->value(), editor_mixer_strip_width));
2128 if ((prop = node.property ("zoom-focus"))) {
2129 set_zoom_focus ((ZoomFocus) atoi (prop->value()));
2132 if ((prop = node.property ("zoom"))) {
2133 reset_zoom (PBD::atof (prop->value()));
2136 if ((prop = node.property ("snap-to"))) {
2137 set_snap_to ((SnapType) atoi (prop->value()));
2140 if ((prop = node.property ("snap-mode"))) {
2141 set_snap_mode ((SnapMode) atoi (prop->value()));
2144 if ((prop = node.property ("mouse-mode"))) {
2145 MouseMode m = str2mousemode(prop->value());
2146 mouse_mode = MouseMode ((int) m + 1); /* lie, force mode switch */
2147 set_mouse_mode (m, true);
2149 mouse_mode = MouseGain; /* lie, to force the mode switch */
2150 set_mouse_mode (MouseObject, true);
2153 if ((prop = node.property ("show-waveforms"))) {
2154 bool yn = (prop->value() == "yes");
2155 _show_waveforms = !yn;
2156 RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("ToggleWaveformVisibility"));
2158 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
2159 /* do it twice to force the change */
2160 tact->set_active (!yn);
2161 tact->set_active (yn);
2165 if ((prop = node.property ("show-waveforms-recording"))) {
2166 bool yn = (prop->value() == "yes");
2167 _show_waveforms_recording = !yn;
2168 RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("ToggleWaveformsWhileRecording"));
2170 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
2171 /* do it twice to force the change */
2172 tact->set_active (!yn);
2173 tact->set_active (yn);
2177 if ((prop = node.property ("show-measures"))) {
2178 bool yn = (prop->value() == "yes");
2179 _show_measures = !yn;
2180 RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("ToggleMeasureVisibility"));
2182 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
2183 /* do it twice to force the change */
2184 tact->set_active (!yn);
2185 tact->set_active (yn);
2189 if ((prop = node.property ("follow-playhead"))) {
2190 bool yn = (prop->value() == "yes");
2191 set_follow_playhead (yn);
2192 RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("toggle-follow-playhead"));
2194 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
2195 if (tact->get_active() != yn) {
2196 tact->set_active (yn);
2201 if ((prop = node.property ("region-list-sort-type"))) {
2202 region_list_sort_type = (Editing::RegionListSortType) -1; // force change
2203 reset_region_list_sort_type(str2regionlistsorttype(prop->value()));
2206 if ((prop = node.property ("xfades-visible"))) {
2207 bool yn = (prop->value() == "yes");
2208 _xfade_visibility = !yn;
2209 // set_xfade_visibility (yn);
2212 if ((prop = node.property ("show-editor-mixer"))) {
2214 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("show-editor-mixer"));
2217 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
2218 bool yn = (prop->value() == X_("yes"));
2220 /* do it twice to force the change */
2222 tact->set_active (!yn);
2223 tact->set_active (yn);
2232 Editor::get_state ()
2234 XMLNode* node = new XMLNode ("Editor");
2237 _id.print (buf, sizeof (buf));
2238 node->add_property ("id", buf);
2240 if (is_realized()) {
2241 Glib::RefPtr<Gdk::Window> win = get_window();
2243 int x, y, xoff, yoff, width, height;
2244 win->get_root_origin(x, y);
2245 win->get_position(xoff, yoff);
2246 win->get_size(width, height);
2248 XMLNode* geometry = new XMLNode ("geometry");
2250 snprintf(buf, sizeof(buf), "%d", width);
2251 geometry->add_property("x_size", string(buf));
2252 snprintf(buf, sizeof(buf), "%d", height);
2253 geometry->add_property("y_size", string(buf));
2254 snprintf(buf, sizeof(buf), "%d", x);
2255 geometry->add_property("x_pos", string(buf));
2256 snprintf(buf, sizeof(buf), "%d", y);
2257 geometry->add_property("y_pos", string(buf));
2258 snprintf(buf, sizeof(buf), "%d", xoff);
2259 geometry->add_property("x_off", string(buf));
2260 snprintf(buf, sizeof(buf), "%d", yoff);
2261 geometry->add_property("y_off", string(buf));
2262 snprintf(buf,sizeof(buf), "%d",gtk_paned_get_position (static_cast<Paned*>(&edit_pane)->gobj()));
2263 geometry->add_property("edit_pane_pos", string(buf));
2265 node->add_child_nocopy (*geometry);
2268 maybe_add_mixer_strip_width (*node);
2270 snprintf (buf, sizeof(buf), "%d", (int) zoom_focus);
2271 node->add_property ("zoom-focus", buf);
2272 snprintf (buf, sizeof(buf), "%f", frames_per_unit);
2273 node->add_property ("zoom", buf);
2274 snprintf (buf, sizeof(buf), "%d", (int) snap_type);
2275 node->add_property ("snap-to", buf);
2276 snprintf (buf, sizeof(buf), "%d", (int) snap_mode);
2277 node->add_property ("snap-mode", buf);
2279 snprintf (buf, sizeof (buf), "%" PRIu32, playhead_cursor->current_frame);
2280 node->add_property ("playhead", buf);
2281 snprintf (buf, sizeof (buf), "%" PRIu32, edit_cursor->current_frame);
2282 node->add_property ("edit-cursor", buf);
2284 node->add_property ("show-waveforms", _show_waveforms ? "yes" : "no");
2285 node->add_property ("show-waveforms-recording", _show_waveforms_recording ? "yes" : "no");
2286 node->add_property ("show-measures", _show_measures ? "yes" : "no");
2287 node->add_property ("follow-playhead", _follow_playhead ? "yes" : "no");
2288 node->add_property ("xfades-visible", _xfade_visibility ? "yes" : "no");
2289 node->add_property ("region-list-sort-type", enum2str(region_list_sort_type));
2290 node->add_property ("mouse-mode", enum2str(mouse_mode));
2292 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("show-editor-mixer"));
2294 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
2295 node->add_property (X_("show-editor-mixer"), tact->get_active() ? "yes" : "no");
2304 Editor::trackview_by_y_position (double y)
2306 for (TrackViewList::iterator iter = track_views.begin(); iter != track_views.end(); ++iter) {
2310 if ((tv = (*iter)->covers_y_position (y)) != 0) {
2319 Editor::snap_to (nframes64_t& start, int32_t direction, bool for_mark)
2321 Location* before = 0;
2322 Location* after = 0;
2328 const nframes64_t one_second = session->frame_rate();
2329 const nframes64_t one_minute = session->frame_rate() * 60;
2330 const nframes64_t one_smpte_second = (nframes64_t)(rint(session->smpte_frames_per_second()) * session->frames_per_smpte_frame());
2331 nframes64_t one_smpte_minute = (nframes64_t)(rint(session->smpte_frames_per_second()) * session->frames_per_smpte_frame() * 60);
2332 nframes64_t presnap = start;
2334 switch (snap_type) {
2340 start = (nframes_t) ceil ((double) start / (one_second / 75)) * (one_second / 75);
2342 start = (nframes_t) floor ((double) start / (one_second / 75)) * (one_second / 75);
2346 case SnapToSMPTEFrame:
2347 if (fmod((double)start, (double)session->frames_per_smpte_frame()) > (session->frames_per_smpte_frame() / 2)) {
2348 start = (nframes_t) (ceil ((double) start / session->frames_per_smpte_frame()) * session->frames_per_smpte_frame());
2350 start = (nframes_t) (floor ((double) start / session->frames_per_smpte_frame()) * session->frames_per_smpte_frame());
2354 case SnapToSMPTESeconds:
2355 if (session->smpte_offset_negative())
2357 start += session->smpte_offset ();
2359 start -= session->smpte_offset ();
2361 if (start % one_smpte_second > one_smpte_second / 2) {
2362 start = (nframes_t) ceil ((double) start / one_smpte_second) * one_smpte_second;
2364 start = (nframes_t) floor ((double) start / one_smpte_second) * one_smpte_second;
2367 if (session->smpte_offset_negative())
2369 start -= session->smpte_offset ();
2371 start += session->smpte_offset ();
2375 case SnapToSMPTEMinutes:
2376 if (session->smpte_offset_negative())
2378 start += session->smpte_offset ();
2380 start -= session->smpte_offset ();
2382 if (start % one_smpte_minute > one_smpte_minute / 2) {
2383 start = (nframes_t) ceil ((double) start / one_smpte_minute) * one_smpte_minute;
2385 start = (nframes_t) floor ((double) start / one_smpte_minute) * one_smpte_minute;
2387 if (session->smpte_offset_negative())
2389 start -= session->smpte_offset ();
2391 start += session->smpte_offset ();
2396 if (start % one_second > one_second / 2) {
2397 start = (nframes_t) ceil ((double) start / one_second) * one_second;
2399 start = (nframes_t) floor ((double) start / one_second) * one_second;
2404 if (start % one_minute > one_minute / 2) {
2405 start = (nframes_t) ceil ((double) start / one_minute) * one_minute;
2407 start = (nframes_t) floor ((double) start / one_minute) * one_minute;
2412 start = session->tempo_map().round_to_bar (start, direction);
2416 start = session->tempo_map().round_to_beat (start, direction);
2419 case SnapToAThirtysecondBeat:
2420 start = session->tempo_map().round_to_beat_subdivision (start, 32);
2423 case SnapToASixteenthBeat:
2424 start = session->tempo_map().round_to_beat_subdivision (start, 16);
2427 case SnapToAEighthBeat:
2428 start = session->tempo_map().round_to_beat_subdivision (start, 8);
2431 case SnapToAQuarterBeat:
2432 start = session->tempo_map().round_to_beat_subdivision (start, 4);
2435 case SnapToAThirdBeat:
2436 start = session->tempo_map().round_to_beat_subdivision (start, 3);
2439 case SnapToEditCursor:
2440 start = edit_cursor->current_frame;
2448 before = session->locations()->first_location_before (start);
2449 after = session->locations()->first_location_after (start);
2451 if (direction < 0) {
2453 start = before->start();
2457 } else if (direction > 0) {
2459 start = after->start();
2461 start = session->current_end_frame();
2466 /* find nearest of the two */
2467 if ((start - before->start()) < (after->start() - start)) {
2468 start = before->start();
2470 start = after->start();
2473 start = before->start();
2476 start = after->start();
2483 case SnapToRegionStart:
2484 case SnapToRegionEnd:
2485 case SnapToRegionSync:
2486 case SnapToRegionBoundary:
2487 if (!region_boundary_cache.empty()) {
2488 vector<nframes_t>::iterator i;
2490 if (direction > 0) {
2491 i = std::upper_bound (region_boundary_cache.begin(), region_boundary_cache.end(), start);
2493 i = std::lower_bound (region_boundary_cache.begin(), region_boundary_cache.end(), start);
2496 if (i != region_boundary_cache.end()) {
2499 start = region_boundary_cache.back();
2505 switch (snap_mode) {
2511 if (presnap > start) {
2512 if (presnap > (start + unit_to_frame(snap_threshold))) {
2516 } else if (presnap < start) {
2517 if (presnap < (start - unit_to_frame(snap_threshold))) {
2529 Editor::setup_toolbar ()
2533 const guint32 FUDGE = 18; // Combo's are stupid - they steal space from the entry for the button
2536 /* Mode Buttons (tool selection) */
2538 vector<ToggleButton *> mouse_mode_buttons;
2540 mouse_move_button.add (*(manage (new Image (::get_icon("tool_object")))));
2541 mouse_move_button.set_relief(Gtk::RELIEF_NONE);
2542 mouse_mode_buttons.push_back (&mouse_move_button);
2543 mouse_select_button.add (*(manage (new Image (get_xpm("tool_range.xpm")))));
2544 mouse_select_button.set_relief(Gtk::RELIEF_NONE);
2545 mouse_mode_buttons.push_back (&mouse_select_button);
2546 mouse_gain_button.add (*(manage (new Image (::get_icon("tool_gain")))));
2547 mouse_gain_button.set_relief(Gtk::RELIEF_NONE);
2548 mouse_mode_buttons.push_back (&mouse_gain_button);
2549 mouse_zoom_button.add (*(manage (new Image (::get_icon("tool_zoom")))));
2550 mouse_zoom_button.set_relief(Gtk::RELIEF_NONE);
2551 mouse_mode_buttons.push_back (&mouse_zoom_button);
2552 mouse_timefx_button.add (*(manage (new Image (::get_icon("tool_stretch")))));
2553 mouse_timefx_button.set_relief(Gtk::RELIEF_NONE);
2554 mouse_mode_buttons.push_back (&mouse_timefx_button);
2555 mouse_audition_button.add (*(manage (new Image (::get_icon("tool_audition")))));
2556 mouse_audition_button.set_relief(Gtk::RELIEF_NONE);
2557 mouse_mode_buttons.push_back (&mouse_audition_button);
2559 mouse_mode_button_set = new GroupedButtons (mouse_mode_buttons);
2561 HBox* mode_box = manage(new HBox);
2562 mode_box->set_border_width (2);
2563 mode_box->set_spacing(4);
2564 mouse_mode_button_box.set_spacing(1);
2565 mouse_mode_button_box.pack_start(mouse_move_button, true, true);
2566 mouse_mode_button_box.pack_start(mouse_select_button, true, true);
2567 mouse_mode_button_box.pack_start(mouse_zoom_button, true, true);
2568 mouse_mode_button_box.pack_start(mouse_gain_button, true, true);
2569 mouse_mode_button_box.pack_start(mouse_timefx_button, true, true);
2570 mouse_mode_button_box.pack_start(mouse_audition_button, true, true);
2571 mouse_mode_button_box.set_homogeneous(true);
2573 vector<string> edit_mode_strings;
2574 edit_mode_strings.push_back (edit_mode_to_string (Splice));
2575 edit_mode_strings.push_back (edit_mode_to_string (Slide));
2577 edit_mode_selector.set_name ("EditModeSelector");
2578 Gtkmm2ext::set_size_request_to_display_given_text (edit_mode_selector, longest (edit_mode_strings).c_str(), 2+FUDGE, 10);
2579 set_popdown_strings (edit_mode_selector, edit_mode_strings);
2580 edit_mode_selector.signal_changed().connect (mem_fun(*this, &Editor::edit_mode_selection_done));
2582 mode_box->pack_start(edit_mode_selector);
2583 mode_box->pack_start(mouse_mode_button_box);
2585 mouse_mode_tearoff = manage (new TearOff (*mode_box));
2586 mouse_mode_tearoff->set_name ("MouseModeBase");
2588 mouse_mode_tearoff->Detach.connect (bind (mem_fun(*this, &Editor::detach_tearoff), static_cast<Box*>(&toolbar_hbox),
2589 &mouse_mode_tearoff->tearoff_window()));
2590 mouse_mode_tearoff->Attach.connect (bind (mem_fun(*this, &Editor::reattach_tearoff), static_cast<Box*> (&toolbar_hbox),
2591 &mouse_mode_tearoff->tearoff_window(), 1));
2592 mouse_mode_tearoff->Hidden.connect (bind (mem_fun(*this, &Editor::detach_tearoff), static_cast<Box*>(&toolbar_hbox),
2593 &mouse_mode_tearoff->tearoff_window()));
2594 mouse_mode_tearoff->Visible.connect (bind (mem_fun(*this, &Editor::reattach_tearoff), static_cast<Box*> (&toolbar_hbox),
2595 &mouse_mode_tearoff->tearoff_window(), 1));
2597 mouse_move_button.set_name ("MouseModeButton");
2598 mouse_select_button.set_name ("MouseModeButton");
2599 mouse_gain_button.set_name ("MouseModeButton");
2600 mouse_zoom_button.set_name ("MouseModeButton");
2601 mouse_timefx_button.set_name ("MouseModeButton");
2602 mouse_audition_button.set_name ("MouseModeButton");
2604 ARDOUR_UI::instance()->tooltips().set_tip (mouse_move_button, _("Select/Move Objects"));
2605 ARDOUR_UI::instance()->tooltips().set_tip (mouse_select_button, _("Select/Move Ranges"));
2606 ARDOUR_UI::instance()->tooltips().set_tip (mouse_gain_button, _("Draw Gain Automation"));
2607 ARDOUR_UI::instance()->tooltips().set_tip (mouse_zoom_button, _("Select Zoom Range"));
2608 ARDOUR_UI::instance()->tooltips().set_tip (mouse_timefx_button, _("Stretch/Shrink Regions"));
2609 ARDOUR_UI::instance()->tooltips().set_tip (mouse_audition_button, _("Listen to Specific Regions"));
2611 mouse_move_button.unset_flags (CAN_FOCUS);
2612 mouse_select_button.unset_flags (CAN_FOCUS);
2613 mouse_gain_button.unset_flags (CAN_FOCUS);
2614 mouse_zoom_button.unset_flags (CAN_FOCUS);
2615 mouse_timefx_button.unset_flags (CAN_FOCUS);
2616 mouse_audition_button.unset_flags (CAN_FOCUS);
2618 mouse_select_button.signal_toggled().connect (bind (mem_fun(*this, &Editor::mouse_mode_toggled), Editing::MouseRange));
2619 mouse_select_button.signal_button_release_event().connect (mem_fun(*this, &Editor::mouse_select_button_release));
2621 mouse_move_button.signal_toggled().connect (bind (mem_fun(*this, &Editor::mouse_mode_toggled), Editing::MouseObject));
2622 mouse_gain_button.signal_toggled().connect (bind (mem_fun(*this, &Editor::mouse_mode_toggled), Editing::MouseGain));
2623 mouse_zoom_button.signal_toggled().connect (bind (mem_fun(*this, &Editor::mouse_mode_toggled), Editing::MouseZoom));
2624 mouse_timefx_button.signal_toggled().connect (bind (mem_fun(*this, &Editor::mouse_mode_toggled), Editing::MouseTimeFX));
2625 mouse_audition_button.signal_toggled().connect (bind (mem_fun(*this, &Editor::mouse_mode_toggled), Editing::MouseAudition));
2627 // mouse_move_button.set_active (true);
2632 zoom_box.set_spacing (1);
2633 zoom_box.set_border_width (2);
2635 zoom_in_button.set_name ("EditorTimeButton");
2636 zoom_in_button.set_size_request(-1,16);
2637 zoom_in_button.add (*(manage (new Image (::get_icon("zoom_in")))));
2638 zoom_in_button.signal_clicked().connect (bind (mem_fun(*this, &Editor::temporal_zoom_step), false));
2639 ARDOUR_UI::instance()->tooltips().set_tip (zoom_in_button, _("Zoom In"));
2641 zoom_out_button.set_name ("EditorTimeButton");
2642 zoom_out_button.set_size_request(-1,16);
2643 zoom_out_button.add (*(manage (new Image (::get_icon("zoom_out")))));
2644 zoom_out_button.signal_clicked().connect (bind (mem_fun(*this, &Editor::temporal_zoom_step), true));
2645 ARDOUR_UI::instance()->tooltips().set_tip (zoom_out_button, _("Zoom Out"));
2647 zoom_out_full_button.set_name ("EditorTimeButton");
2648 zoom_out_full_button.set_size_request(-1,16);
2649 zoom_out_full_button.add (*(manage (new Image (::get_icon("zoom_full")))));
2650 zoom_out_full_button.signal_clicked().connect (mem_fun(*this, &Editor::temporal_zoom_session));
2651 ARDOUR_UI::instance()->tooltips().set_tip (zoom_out_full_button, _("Zoom to Session"));
2653 zoom_focus_selector.set_name ("ZoomFocusSelector");
2654 Gtkmm2ext::set_size_request_to_display_given_text (zoom_focus_selector, "Edit Cursor", FUDGE, 0);
2655 set_popdown_strings (zoom_focus_selector, zoom_focus_strings);
2656 zoom_focus_selector.signal_changed().connect (mem_fun(*this, &Editor::zoom_focus_selection_done));
2657 ARDOUR_UI::instance()->tooltips().set_tip (zoom_focus_selector, _("Zoom focus"));
2659 zoom_box.pack_start (zoom_focus_selector, true, true);
2660 zoom_box.pack_start (zoom_out_button, false, false);
2661 zoom_box.pack_start (zoom_in_button, false, false);
2662 zoom_box.pack_start (zoom_out_full_button, false, false);
2664 /* Edit Cursor / Snap */
2666 snap_box.set_spacing (1);
2667 snap_box.set_border_width (2);
2669 snap_type_selector.set_name ("SnapTypeSelector");
2670 Gtkmm2ext::set_size_request_to_display_given_text (snap_type_selector, "SMPTE Seconds", 2+FUDGE, 10);
2671 set_popdown_strings (snap_type_selector, snap_type_strings);
2672 snap_type_selector.signal_changed().connect (mem_fun(*this, &Editor::snap_type_selection_done));
2673 ARDOUR_UI::instance()->tooltips().set_tip (snap_type_selector, _("Unit to snap cursors and ranges to"));
2675 snap_mode_selector.set_name ("SnapModeSelector");
2676 Gtkmm2ext::set_size_request_to_display_given_text (snap_mode_selector, "Magnetic Snap", 2+FUDGE, 10);
2677 set_popdown_strings (snap_mode_selector, snap_mode_strings);
2678 snap_mode_selector.signal_changed().connect (mem_fun(*this, &Editor::snap_mode_selection_done));
2680 snap_box.pack_start (edit_cursor_clock, false, false);
2681 snap_box.pack_start (snap_mode_selector, false, false);
2682 snap_box.pack_start (snap_type_selector, false, false);
2687 HBox *nudge_box = manage (new HBox);
2688 nudge_box->set_spacing(1);
2689 nudge_box->set_border_width (2);
2691 nudge_forward_button.signal_clicked().connect (bind (mem_fun(*this, &Editor::nudge_forward), false));
2692 nudge_backward_button.signal_clicked().connect (bind (mem_fun(*this, &Editor::nudge_backward), false));
2694 nudge_box->pack_start (nudge_backward_button, false, false);
2695 nudge_box->pack_start (nudge_forward_button, false, false);
2696 nudge_box->pack_start (nudge_clock, false, false);
2699 /* Pack everything in... */
2701 HBox* hbox = new HBox;
2702 hbox->set_spacing(10);
2704 tools_tearoff = new TearOff (*hbox);
2705 tools_tearoff->set_name ("MouseModeBase");
2707 tools_tearoff->Detach.connect (bind (mem_fun(*this, &Editor::detach_tearoff), static_cast<Box*>(&toolbar_hbox),
2708 &tools_tearoff->tearoff_window()));
2709 tools_tearoff->Attach.connect (bind (mem_fun(*this, &Editor::reattach_tearoff), static_cast<Box*> (&toolbar_hbox),
2710 &tools_tearoff->tearoff_window(), 0));
2711 tools_tearoff->Hidden.connect (bind (mem_fun(*this, &Editor::detach_tearoff), static_cast<Box*>(&toolbar_hbox),
2712 &tools_tearoff->tearoff_window()));
2713 tools_tearoff->Visible.connect (bind (mem_fun(*this, &Editor::reattach_tearoff), static_cast<Box*> (&toolbar_hbox),
2714 &tools_tearoff->tearoff_window(), 0));
2716 toolbar_hbox.set_spacing (10);
2717 toolbar_hbox.set_border_width (1);
2719 toolbar_hbox.pack_start (*mouse_mode_tearoff, false, false);
2720 toolbar_hbox.pack_start (*tools_tearoff, false, false);
2723 hbox->pack_start (snap_box, false, false);
2724 // hbox->pack_start (zoom_box, false, false);
2725 hbox->pack_start (*nudge_box, false, false);
2729 toolbar_base.set_name ("ToolBarBase");
2730 toolbar_base.add (toolbar_hbox);
2732 toolbar_frame.set_shadow_type (SHADOW_OUT);
2733 toolbar_frame.set_name ("BaseFrame");
2734 toolbar_frame.add (toolbar_base);
2738 Editor::convert_drop_to_paths (vector<ustring>& paths,
2739 const RefPtr<Gdk::DragContext>& context,
2742 const SelectionData& data,
2751 vector<ustring> uris = data.get_uris();
2753 cerr << "there were " << uris.size() << " in that drag data\n";
2757 /* This is seriously fucked up. Nautilus doesn't say that its URI lists
2758 are actually URI lists. So do it by hand.
2761 if (data.get_target() != "text/plain") {
2765 /* Parse the "uri-list" format that Nautilus provides,
2766 where each pathname is delimited by \r\n
2769 const char* p = data.get_text().c_str();
2776 while (g_ascii_isspace (*p))
2780 while (*q && (*q != '\n') && (*q != '\r'))
2786 while (q > p && g_ascii_isspace (*q))
2791 uris.push_back (ustring (p, q - p + 1));
2795 p = strchr (p, '\n');
2805 for (vector<ustring>::iterator i = uris.begin(); i != uris.end(); ++i) {
2807 if ((*i).substr (0,7) == "file://") {
2811 PBD::url_decode (p);
2813 // scan forward past three slashes
2815 ustring::size_type slashcnt = 0;
2816 ustring::size_type n = 0;
2817 ustring::iterator x = p.begin();
2819 while (slashcnt < 3 && x != p.end()) {
2822 } else if (slashcnt == 3) {
2829 if (slashcnt != 3 || x == p.end()) {
2830 error << _("malformed URL passed to drag-n-drop code") << endmsg;
2834 paths.push_back (p.substr (n - 1));
2842 Editor::new_tempo_section ()
2848 Editor::map_transport_state ()
2850 ENSURE_GUI_THREAD (mem_fun(*this, &Editor::map_transport_state));
2852 if (session->transport_stopped()) {
2853 have_pending_keyboard_selection = false;
2856 update_loop_range_view (true);
2861 Editor::State::State ()
2863 selection = new Selection;
2866 Editor::State::~State ()
2872 Editor::get_memento () const
2874 State *state = new State;
2876 store_state (*state);
2877 return bind (mem_fun (*(const_cast<Editor*>(this)), &Editor::restore_state), state);
2881 Editor::store_state (State& state) const
2883 *state.selection = *selection;
2887 Editor::restore_state (State *state)
2889 if (*selection == *state->selection) {
2893 *selection = *state->selection;
2894 time_selection_changed ();
2895 region_selection_changed ();
2897 /* XXX other selection change handlers? */
2901 Editor::begin_reversible_command (string name)
2904 // before = &get_state();
2905 session->begin_reversible_command (name);
2910 Editor::commit_reversible_command ()
2913 // session->commit_reversible_command (new MementoCommand<Editor>(*this, before, &get_state()));
2914 session->commit_reversible_command ();
2919 Editor::set_edit_group_solo (Route& route, bool yn)
2921 RouteGroup *edit_group;
2923 if ((edit_group = route.edit_group()) != 0) {
2924 edit_group->apply (&Route::set_solo, yn, this);
2926 route.set_solo (yn, this);
2931 Editor::set_edit_group_mute (Route& route, bool yn)
2933 RouteGroup *edit_group = 0;
2935 if ((edit_group == route.edit_group()) != 0) {
2936 edit_group->apply (&Route::set_mute, yn, this);
2938 route.set_mute (yn, this);
2943 Editor::history_changed ()
2947 if (undo_action && session) {
2948 if (session->undo_depth() == 0) {
2951 label = string_compose(_("Undo (%1)"), session->next_undo());
2953 undo_action->property_label() = label;
2956 if (redo_action && session) {
2957 if (session->redo_depth() == 0) {
2960 label = string_compose(_("Redo (%1)"), session->next_redo());
2962 redo_action->property_label() = label;
2967 Editor::duplicate_dialog (bool dup_region)
2969 if (selection->regions.empty() && (selection->time.length() == 0)) {
2973 ArdourDialog win ("duplicate dialog");
2974 Label label (_("Duplicate how many times?"));
2975 Adjustment adjustment (1.0, 1.0, 1000000.0, 1.0, 5.0);
2976 SpinButton spinner (adjustment);
2978 win.get_vbox()->set_spacing (12);
2979 win.get_vbox()->pack_start (label);
2981 /* dialogs have ::add_action_widget() but that puts the spinner in the wrong
2982 place, visually. so do this by hand.
2985 win.get_vbox()->pack_start (spinner);
2986 spinner.signal_activate().connect (sigc::bind (mem_fun (win, &ArdourDialog::response), RESPONSE_ACCEPT));
2991 win.add_button (Stock::OK, RESPONSE_ACCEPT);
2992 win.add_button (Stock::CANCEL, RESPONSE_CANCEL);
2994 win.set_position (WIN_POS_MOUSE);
2996 spinner.grab_focus ();
2998 switch (win.run ()) {
2999 case RESPONSE_ACCEPT:
3005 float times = adjustment.get_value();
3007 if (!selection->regions.empty()) {
3008 duplicate_some_regions (selection->regions, times);
3010 duplicate_selection (times);
3015 Editor::show_verbose_canvas_cursor ()
3017 verbose_canvas_cursor->raise_to_top();
3018 verbose_canvas_cursor->show();
3019 verbose_cursor_visible = true;
3023 Editor::hide_verbose_canvas_cursor ()
3025 verbose_canvas_cursor->hide();
3026 verbose_cursor_visible = false;
3030 Editor::set_verbose_canvas_cursor (const string & txt, double x, double y)
3032 /* XXX get origin of canvas relative to root window,
3033 add x and y and check compared to gdk_screen_{width,height}
3035 verbose_canvas_cursor->property_text() = txt.c_str();
3036 verbose_canvas_cursor->property_x() = x;
3037 verbose_canvas_cursor->property_y() = y;
3041 Editor::set_verbose_canvas_cursor_text (const string & txt)
3043 verbose_canvas_cursor->property_text() = txt.c_str();
3047 Editor::edit_mode_selection_done ()
3053 string choice = edit_mode_selector.get_active_text();
3054 EditMode mode = Slide;
3056 if (choice == _("Splice Edit")) {
3058 } else if (choice == _("Slide Edit")) {
3062 Config->set_edit_mode (mode);
3066 Editor::snap_type_selection_done ()
3068 string choice = snap_type_selector.get_active_text();
3069 SnapType snaptype = SnapToFrame;
3071 if (choice == _("Beats/3")) {
3072 snaptype = SnapToAThirdBeat;
3073 } else if (choice == _("Beats/4")) {
3074 snaptype = SnapToAQuarterBeat;
3075 } else if (choice == _("Beats/8")) {
3076 snaptype = SnapToAEighthBeat;
3077 } else if (choice == _("Beats/16")) {
3078 snaptype = SnapToASixteenthBeat;
3079 } else if (choice == _("Beats/32")) {
3080 snaptype = SnapToAThirtysecondBeat;
3081 } else if (choice == _("Beats")) {
3082 snaptype = SnapToBeat;
3083 } else if (choice == _("Bars")) {
3084 snaptype = SnapToBar;
3085 } else if (choice == _("Marks")) {
3086 snaptype = SnapToMark;
3087 } else if (choice == _("Edit Cursor")) {
3088 snaptype = SnapToEditCursor;
3089 } else if (choice == _("Region starts")) {
3090 snaptype = SnapToRegionStart;
3091 } else if (choice == _("Region ends")) {
3092 snaptype = SnapToRegionEnd;
3093 } else if (choice == _("Region bounds")) {
3094 snaptype = SnapToRegionBoundary;
3095 } else if (choice == _("Region syncs")) {
3096 snaptype = SnapToRegionSync;
3097 } else if (choice == _("CD Frames")) {
3098 snaptype = SnapToCDFrame;
3099 } else if (choice == _("SMPTE Frames")) {
3100 snaptype = SnapToSMPTEFrame;
3101 } else if (choice == _("SMPTE Seconds")) {
3102 snaptype = SnapToSMPTESeconds;
3103 } else if (choice == _("SMPTE Minutes")) {
3104 snaptype = SnapToSMPTEMinutes;
3105 } else if (choice == _("Seconds")) {
3106 snaptype = SnapToSeconds;
3107 } else if (choice == _("Minutes")) {
3108 snaptype = SnapToMinutes;
3109 } else if (choice == _("None")) {
3110 snaptype = SnapToFrame;
3113 RefPtr<RadioAction> ract = snap_type_action (snaptype);
3115 ract->set_active ();
3120 Editor::snap_mode_selection_done ()
3122 string choice = snap_mode_selector.get_active_text();
3123 SnapMode mode = SnapNormal;
3125 if (choice == _("Normal")) {
3127 } else if (choice == _("Magnetic")) {
3128 mode = SnapMagnetic;
3131 RefPtr<RadioAction> ract = snap_mode_action (mode);
3134 ract->set_active (true);
3139 Editor::zoom_focus_selection_done ()
3141 string choice = zoom_focus_selector.get_active_text();
3142 ZoomFocus focus_type = ZoomFocusLeft;
3144 if (choice == _("Left")) {
3145 focus_type = ZoomFocusLeft;
3146 } else if (choice == _("Right")) {
3147 focus_type = ZoomFocusRight;
3148 } else if (choice == _("Center")) {
3149 focus_type = ZoomFocusCenter;
3150 } else if (choice == _("Playhead")) {
3151 focus_type = ZoomFocusPlayhead;
3152 } else if (choice == _("Edit Cursor")) {
3153 focus_type = ZoomFocusEdit;
3156 RefPtr<RadioAction> ract = zoom_focus_action (focus_type);
3159 ract->set_active ();
3164 Editor::edit_controls_button_release (GdkEventButton* ev)
3166 if (Keyboard::is_context_menu_event (ev)) {
3167 ARDOUR_UI::instance()->add_route (this);
3173 Editor::mouse_select_button_release (GdkEventButton* ev)
3175 /* this handles just right-clicks */
3177 if (ev->button != 3) {
3184 Editor::TrackViewList *
3185 Editor::get_valid_views (TimeAxisView* track, RouteGroup* group)
3188 TrackViewList::iterator i;
3190 v = new TrackViewList;
3192 if (track == 0 && group == 0) {
3196 for (i = track_views.begin(); i != track_views.end (); ++i) {
3200 } else if (track != 0 && group == 0 || (track != 0 && group != 0 && !group->is_active())) {
3202 /* just the view for this track
3205 v->push_back (track);
3209 /* views for all tracks in the edit group */
3211 for (i = track_views.begin(); i != track_views.end (); ++i) {
3213 if (group == 0 || (*i)->edit_group() == group) {
3223 Editor::set_zoom_focus (ZoomFocus f)
3225 string str = zoom_focus_strings[(int)f];
3227 if (str != zoom_focus_selector.get_active_text()) {
3228 zoom_focus_selector.set_active_text (str);
3231 if (zoom_focus != f) {
3234 ZoomFocusChanged (); /* EMIT_SIGNAL */
3241 Editor::ensure_float (Window& win)
3243 win.set_transient_for (*this);
3247 Editor::pane_allocation_handler (Allocation &alloc, Paned* which)
3249 /* recover or initialize pane positions. do this here rather than earlier because
3250 we don't want the positions to change the child allocations, which they seem to do.
3256 XMLNode* node = ARDOUR_UI::instance()->editor_settings();
3258 static int32_t done;
3261 if ((geometry = find_named_node (*node, "geometry")) == 0) {
3262 width = default_width;
3263 height = default_height;
3265 width = atoi(geometry->property("x_size")->value());
3266 height = atoi(geometry->property("y_size")->value());
3269 if (which == static_cast<Paned*> (&edit_pane)) {
3275 if (!geometry || (prop = geometry->property ("edit_pane_pos")) == 0) {
3276 /* initial allocation is 90% to canvas, 10% to notebook */
3277 pos = (int) floor (alloc.get_width() * 0.90f);
3278 snprintf (buf, sizeof(buf), "%d", pos);
3280 pos = atoi (prop->value());
3283 if ((done = GTK_WIDGET(edit_pane.gobj())->allocation.width > pos)) {
3284 edit_pane.set_position (pos);
3285 pre_maximal_pane_position = pos;
3291 Editor::detach_tearoff (Box* b, Window* w)
3293 if (tools_tearoff->torn_off() &&
3294 mouse_mode_tearoff->torn_off()) {
3295 top_hbox.remove (toolbar_frame);
3300 Editor::reattach_tearoff (Box* b, Window* w, int32_t n)
3302 if (toolbar_frame.get_parent() == 0) {
3303 top_hbox.pack_end (toolbar_frame);
3308 Editor::set_show_measures (bool yn)
3310 if (_show_measures != yn) {
3313 if ((_show_measures = yn) == true) {
3321 Editor::toggle_follow_playhead ()
3323 RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("toggle-follow-playhead"));
3325 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
3326 set_follow_playhead (tact->get_active());
3331 Editor::set_follow_playhead (bool yn)
3333 if (_follow_playhead != yn) {
3334 if ((_follow_playhead = yn) == true) {
3336 update_current_screen ();
3343 Editor::toggle_xfade_active (boost::weak_ptr<Crossfade> wxfade)
3345 boost::shared_ptr<Crossfade> xfade (wxfade.lock());
3347 xfade->set_active (!xfade->active());
3352 Editor::toggle_xfade_length (boost::weak_ptr<Crossfade> wxfade)
3354 boost::shared_ptr<Crossfade> xfade (wxfade.lock());
3356 xfade->set_follow_overlap (!xfade->following_overlap());
3361 Editor::edit_xfade (boost::weak_ptr<Crossfade> wxfade)
3363 boost::shared_ptr<Crossfade> xfade (wxfade.lock());
3369 CrossfadeEditor cew (*session, xfade, xfade->fade_in().get_min_y(), 1.0);
3373 switch (cew.run ()) {
3374 case RESPONSE_ACCEPT:
3381 xfade->StateChanged (Change (~0));
3385 Editor::playlist_selector () const
3387 return *_playlist_selector;
3391 Editor::get_nudge_distance (nframes_t pos, nframes_t& next)
3395 ret = nudge_clock.current_duration (pos);
3396 next = ret + 1; /* XXXX fix me */
3402 Editor::end_location_changed (Location* location)
3404 ENSURE_GUI_THREAD (bind (mem_fun(*this, &Editor::end_location_changed), location));
3405 reset_scrolling_region ();
3409 Editor::playlist_deletion_dialog (boost::shared_ptr<Playlist> pl)
3411 ArdourDialog dialog ("playlist deletion dialog");
3412 Label label (string_compose (_("Playlist %1 is currently unused.\n"
3413 "If left alone, no audio files used by it will be cleaned.\n"
3414 "If deleted, audio files used by it alone by will cleaned."),
3417 dialog.set_position (WIN_POS_CENTER);
3418 dialog.get_vbox()->pack_start (label);
3422 dialog.add_button (_("Delete playlist"), RESPONSE_ACCEPT);
3423 dialog.add_button (_("Keep playlist"), RESPONSE_REJECT);
3424 dialog.add_button (_("Cancel"), RESPONSE_CANCEL);
3426 switch (dialog.run ()) {
3427 case RESPONSE_ACCEPT:
3428 /* delete the playlist */
3432 case RESPONSE_REJECT:
3433 /* keep the playlist */
3445 Editor::audio_region_selection_covers (nframes_t where)
3447 for (RegionSelection::iterator a = selection->regions.begin(); a != selection->regions.end(); ++a) {
3448 if ((*a)->region()->covers (where)) {
3457 Editor::prepare_for_cleanup ()
3459 cut_buffer->clear_regions ();
3460 cut_buffer->clear_playlists ();
3462 selection->clear_regions ();
3463 selection->clear_playlists ();
3467 Editor::transport_loop_location()
3470 return session->locations()->auto_loop_location();
3477 Editor::transport_punch_location()
3480 return session->locations()->auto_punch_location();
3487 Editor::control_layout_scroll (GdkEventScroll* ev)
3489 switch (ev->direction) {
3491 scroll_tracks_up_line ();
3495 case GDK_SCROLL_DOWN:
3496 scroll_tracks_down_line ();
3500 /* no left/right handling yet */
3508 /** A new snapshot has been selected.
3511 Editor::snapshot_display_selection_changed ()
3513 if (snapshot_display.get_selection()->count_selected_rows() > 0) {
3515 TreeModel::iterator i = snapshot_display.get_selection()->get_selected();
3517 Glib::ustring snap_name = (*i)[snapshot_display_columns.real_name];
3519 if (snap_name.length() == 0) {
3523 if (session->snap_name() == snap_name) {
3527 ARDOUR_UI::instance()->load_session(session->path(), string (snap_name));
3532 Editor::snapshot_display_button_press (GdkEventButton* ev)
3534 if (ev->button == 3) {
3535 /* Right-click on the snapshot list. Work out which snapshot it
3537 Gtk::TreeModel::Path path;
3538 Gtk::TreeViewColumn* col;
3541 snapshot_display.get_path_at_pos ((int) ev->x, (int) ev->y, path, col, cx, cy);
3542 Gtk::TreeModel::iterator iter = snapshot_display_model->get_iter (path);
3544 Gtk::TreeModel::Row row = *iter;
3545 popup_snapshot_context_menu (ev->button, ev->time, row[snapshot_display_columns.real_name]);
3554 /** Pop up the snapshot display context menu.
3555 * @param button Button used to open the menu.
3556 * @param time Menu open time.
3557 * @snapshot_name Name of the snapshot that the menu click was over.
3561 Editor::popup_snapshot_context_menu (int button, int32_t time, Glib::ustring snapshot_name)
3563 using namespace Menu_Helpers;
3565 MenuList& items (snapshot_context_menu.items());
3568 const bool modification_allowed = (session->snap_name() != snapshot_name && session->name() != snapshot_name);
3570 items.push_back (MenuElem (_("Remove"), bind (mem_fun (*this, &Editor::remove_snapshot), snapshot_name)));
3571 if (!modification_allowed) {
3572 items.back().set_sensitive (false);
3575 items.push_back (MenuElem (_("Rename"), bind (mem_fun (*this, &Editor::rename_snapshot), snapshot_name)));
3576 if (!modification_allowed) {
3577 items.back().set_sensitive (false);
3580 snapshot_context_menu.popup (button, time);
3584 Editor::rename_snapshot (Glib::ustring old_name)
3586 ArdourPrompter prompter(true);
3590 prompter.set_name ("Prompter");
3591 prompter.add_button (Gtk::Stock::SAVE, Gtk::RESPONSE_ACCEPT);
3592 prompter.set_prompt (_("New name of snapshot"));
3593 prompter.set_initial_text (old_name);
3595 if (prompter.run() == RESPONSE_ACCEPT) {
3596 prompter.get_result (new_name);
3597 if (new_name.length()) {
3598 session->rename_state (old_name, new_name);
3599 redisplay_snapshots ();
3606 Editor::remove_snapshot (Glib::ustring name)
3608 vector<string> choices;
3610 std::string prompt = string_compose (_("Do you really want to remove snapshot \"%1\" ?\n(cannot be undone)"), name);
3612 choices.push_back (_("No, do nothing."));
3613 choices.push_back (_("Yes, remove it."));
3615 Gtkmm2ext::Choice prompter (prompt, choices);
3617 if (prompter.run () == 1) {
3618 session->remove_state (name);
3619 redisplay_snapshots ();
3624 Editor::redisplay_snapshots ()
3630 vector<string*>* states;
3632 if ((states = session->possible_states()) == 0) {
3636 snapshot_display_model->clear ();
3638 for (vector<string*>::iterator i = states->begin(); i != states->end(); ++i) {
3639 string statename = *(*i);
3640 TreeModel::Row row = *(snapshot_display_model->append());
3642 /* this lingers on in case we ever want to change the visible
3643 name of the snapshot.
3646 string display_name;
3647 display_name = statename;
3649 if (statename == session->snap_name()) {
3650 snapshot_display.get_selection()->select(row);
3653 row[snapshot_display_columns.visible_name] = display_name;
3654 row[snapshot_display_columns.real_name] = statename;
3661 Editor::session_state_saved (string snap_name)
3663 ENSURE_GUI_THREAD (bind (mem_fun(*this, &Editor::session_state_saved), snap_name));
3664 redisplay_snapshots ();
3668 Editor::maximise_editing_space ()
3670 initial_ruler_update_required = true;
3672 mouse_mode_tearoff->set_visible (false);
3673 tools_tearoff->set_visible (false);
3675 pre_maximal_pane_position = edit_pane.get_position();
3676 pre_maximal_editor_width = this->get_width();
3678 if(post_maximal_pane_position == 0) {
3679 post_maximal_pane_position = edit_pane.get_width();
3684 if(post_maximal_editor_width) {
3685 edit_pane.set_position (post_maximal_pane_position -
3686 abs(post_maximal_editor_width - pre_maximal_editor_width));
3688 edit_pane.set_position (post_maximal_pane_position);
3693 Editor::restore_editing_space ()
3695 initial_ruler_update_required = true;
3697 // user changed width of pane during fullscreen
3698 if(post_maximal_pane_position != edit_pane.get_position()) {
3699 post_maximal_pane_position = edit_pane.get_position();
3704 mouse_mode_tearoff->set_visible (true);
3705 tools_tearoff->set_visible (true);
3706 post_maximal_editor_width = this->get_width();
3709 edit_pane.set_position (
3710 pre_maximal_pane_position + abs(this->get_width() - pre_maximal_editor_width)
3715 Editor::new_playlists ()
3717 begin_reversible_command (_("new playlists"));
3718 mapover_audio_tracks (mem_fun (*this, &Editor::mapped_use_new_playlist));
3719 commit_reversible_command ();
3723 Editor::copy_playlists ()
3725 begin_reversible_command (_("copy playlists"));
3726 mapover_audio_tracks (mem_fun (*this, &Editor::mapped_use_copy_playlist));
3727 commit_reversible_command ();
3731 Editor::clear_playlists ()
3733 begin_reversible_command (_("clear playlists"));
3734 mapover_audio_tracks (mem_fun (*this, &Editor::mapped_clear_playlist));
3735 commit_reversible_command ();
3739 Editor::mapped_use_new_playlist (AudioTimeAxisView& atv, uint32_t sz)
3741 atv.use_new_playlist (sz > 1 ? false : true);
3745 Editor::mapped_use_copy_playlist (AudioTimeAxisView& atv, uint32_t sz)
3747 atv.use_copy_playlist (sz > 1 ? false : true);
3751 Editor::mapped_clear_playlist (AudioTimeAxisView& atv, uint32_t sz)
3753 atv.clear_playlist ();
3757 Editor::on_key_press_event (GdkEventKey* ev)
3759 return key_press_focus_accelerator_handler (*this, ev);
3763 Editor::reset_x_origin (nframes_t frame)
3765 queue_visual_change (frame);
3769 Editor::reset_zoom (double fpu)
3771 queue_visual_change (fpu);
3775 Editor::reposition_and_zoom (nframes_t frame, double fpu)
3777 reset_x_origin (frame);
3782 Editor::set_frames_per_unit (double fpu)
3786 /* this is the core function that controls the zoom level of the canvas. it is called
3787 whenever one or more calls are made to reset_zoom(). it executes in an idle handler.
3790 if (fpu == frames_per_unit) {
3798 // convert fpu to frame count
3800 frames = (nframes_t) floor (fpu * canvas_width);
3802 /* don't allow zooms that fit more than the maximum number
3803 of frames into an 800 pixel wide space.
3806 if (max_frames / fpu < 800.0) {
3810 if (fpu == frames_per_unit) {
3814 frames_per_unit = fpu;
3816 if (frames != zoom_range_clock.current_duration()) {
3817 zoom_range_clock.set (frames);
3820 if (mouse_mode == MouseRange && selection->time.start () != selection->time.end_frame ()) {
3821 if (!selection->tracks.empty()) {
3822 for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
3823 (*i)->reshow_selection (selection->time);
3826 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
3827 (*i)->reshow_selection (selection->time);
3832 ZoomChanged (); /* EMIT_SIGNAL */
3834 reset_hscrollbar_stepping ();
3835 reset_scrolling_region ();
3837 if (edit_cursor) edit_cursor->set_position (edit_cursor->current_frame);
3838 if (playhead_cursor) playhead_cursor->set_position (playhead_cursor->current_frame);
3844 Editor::queue_visual_change (nframes_t where)
3846 pending_visual_change.pending = VisualChange::Type (pending_visual_change.pending | VisualChange::TimeOrigin);
3847 pending_visual_change.time_origin = where;
3849 if (pending_visual_change.idle_handler_id < 0) {
3850 pending_visual_change.idle_handler_id = g_idle_add (_idle_visual_changer, this);
3855 Editor::queue_visual_change (double fpu)
3857 pending_visual_change.pending = VisualChange::Type (pending_visual_change.pending | VisualChange::ZoomLevel);
3858 pending_visual_change.frames_per_unit = fpu;
3860 if (pending_visual_change.idle_handler_id < 0) {
3861 pending_visual_change.idle_handler_id = g_idle_add_full (G_PRIORITY_HIGH_IDLE, _idle_visual_changer, this, 0);
3866 Editor::_idle_visual_changer (void* arg)
3868 return static_cast<Editor*>(arg)->idle_visual_changer ();
3872 Editor::idle_visual_changer ()
3874 VisualChange::Type p = pending_visual_change.pending;
3876 pending_visual_change.pending = (VisualChange::Type) 0;
3877 pending_visual_change.idle_handler_id = -1;
3879 if (p & VisualChange::ZoomLevel) {
3880 set_frames_per_unit (pending_visual_change.frames_per_unit);
3883 if (p & VisualChange::TimeOrigin) {
3884 if (pending_visual_change.time_origin != leftmost_frame) {
3885 horizontal_adjustment.set_value (pending_visual_change.time_origin/frames_per_unit);
3886 /* the signal handler will do the rest */
3888 update_fixed_rulers();
3889 redisplay_tempo (true);
3893 return 0; /* this is always a one-shot call */
3896 struct EditorOrderTimeAxisSorter {
3897 bool operator() (const TimeAxisView* a, const TimeAxisView* b) const {
3898 return a->order < b->order;
3903 Editor::sort_track_selection ()
3905 EditorOrderTimeAxisSorter cmp;
3906 selection->tracks.sort (cmp);
3910 Editor::edit_cursor_position(bool sync)
3912 if (sync && edit_cursor->current_frame != edit_cursor_clock.current_time()) {
3913 edit_cursor_clock.set(edit_cursor->current_frame, true);
3916 return edit_cursor->current_frame;
3920 Editor::set_loop_range (nframes_t start, nframes_t end, string cmd)
3922 if (!session) return;
3924 begin_reversible_command (cmd);
3928 if ((tll = transport_loop_location()) == 0) {
3929 Location* loc = new Location (start, end, _("Loop"), Location::IsAutoLoop);
3930 XMLNode &before = session->locations()->get_state();
3931 session->locations()->add (loc, true);
3932 session->set_auto_loop_location (loc);
3933 XMLNode &after = session->locations()->get_state();
3934 session->add_command (new MementoCommand<Locations>(*(session->locations()), &before, &after));
3937 XMLNode &before = tll->get_state();
3938 tll->set_hidden (false, this);
3939 tll->set (start, end);
3940 XMLNode &after = tll->get_state();
3941 session->add_command (new MementoCommand<Location>(*tll, &before, &after));
3944 commit_reversible_command ();
3948 Editor::set_punch_range (nframes_t start, nframes_t end, string cmd)
3950 if (!session) return;
3952 begin_reversible_command (cmd);
3956 if ((tpl = transport_punch_location()) == 0) {
3957 Location* loc = new Location (start, end, _("Loop"), Location::IsAutoPunch);
3958 XMLNode &before = session->locations()->get_state();
3959 session->locations()->add (loc, true);
3960 session->set_auto_loop_location (loc);
3961 XMLNode &after = session->locations()->get_state();
3962 session->add_command (new MementoCommand<Locations>(*(session->locations()), &before, &after));
3965 XMLNode &before = tpl->get_state();
3966 tpl->set_hidden (false, this);
3967 tpl->set (start, end);
3968 XMLNode &after = tpl->get_state();
3969 session->add_command (new MementoCommand<Location>(*tpl, &before, &after));
3972 commit_reversible_command ();