X-Git-Url: https://main.carlh.net/gitweb/?a=blobdiff_plain;f=gtk2_ardour%2Feditor.cc;h=c7956386ced6848b3058a29d7e9122f12b3c9bbc;hb=eb3f77df5748e81c4a6bfe737cd9b5a3d721a86c;hp=0f62f48c2a597c9297482306b4eef17ce17c9394;hpb=78d7d5fbd3cfb62097f002e81ab35b02f99db806;p=ardour.git diff --git a/gtk2_ardour/editor.cc b/gtk2_ardour/editor.cc index 0f62f48c2a..c7956386ce 100644 --- a/gtk2_ardour/editor.cc +++ b/gtk2_ardour/editor.cc @@ -1,5 +1,5 @@ /* - Copyright (C) 2000 Paul Davis + Copyright (C) 2000-2006 Paul Davis This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -26,8 +26,7 @@ #include -#include - +#include #include #include @@ -49,8 +48,9 @@ #include #include +#include "control_protocol.h" + #include "ardour_ui.h" -#include "check_mark.h" #include "editor.h" #include "grouped_buttons.h" #include "keyboard.h" @@ -60,7 +60,6 @@ #include "rgb_macros.h" #include "selection.h" #include "streamview.h" -#include "simpleline.h" #include "time_axis_view.h" #include "utils.h" #include "crossfade_view.h" @@ -69,8 +68,13 @@ #include "crossfade_edit.h" #include "audio_time_axis.h" #include "canvas_impl.h" +#include "actions.h" #include "gui_thread.h" +#ifdef FFT_ANALYSIS +#include "analysis_window.h" +#endif + #include "i18n.h" /* */ @@ -85,9 +89,9 @@ using namespace Glib; using namespace Gtkmm2ext; using namespace Editing; -/* XXX this is a hack. it ought to be the maximum value of an jack_nframes_t */ +using PBD::internationalize; +using PBD::atoi; -const double max_canvas_coordinate = 100000000.0; const double Editor::timebar_height = 15.0; #include "editor_xpms" @@ -150,14 +154,28 @@ Gdk::Cursor* Editor::zoom_cursor = 0; Gdk::Cursor* Editor::time_fx_cursor = 0; Gdk::Cursor* Editor::fader_cursor = 0; Gdk::Cursor* Editor::speaker_cursor = 0; -Gdk::Cursor* Editor::null_cursor = 0; Gdk::Cursor* Editor::wait_cursor = 0; Gdk::Cursor* Editor::timebar_cursor = 0; -GdkPixmap *Editor::check_pixmap = 0; -GdkBitmap *Editor::check_mask = 0; -GdkPixmap *Editor::empty_pixmap = 0; -GdkBitmap *Editor::empty_mask = 0; +void +show_me_the_size (Requisition* r, const char* what) +{ + cerr << "size of " << what << " = " << r->width << " x " << r->height << endl; +} + +void +check_adjustment (Gtk::Adjustment* adj) +{ + cerr << "CHANGE adj = " + << adj->get_lower () << ' ' + << adj->get_upper () << ' ' + << adj->get_value () << ' ' + << adj->get_step_increment () << ' ' + << adj->get_page_increment () << ' ' + << adj->get_page_size () << ' ' + << endl; + +} Editor::Editor (AudioEngine& eng) : engine (eng), @@ -175,12 +193,15 @@ Editor::Editor (AudioEngine& eng) transport_mark_label (_("Loop/Punch Ranges")), edit_packer (3, 3, false), - edit_hscroll_left_arrow (Gtk::ARROW_LEFT, Gtk::SHADOW_OUT), - edit_hscroll_right_arrow (Gtk::ARROW_RIGHT, Gtk::SHADOW_OUT), - /* tool bar related */ + /* the values here don't matter: layout widgets + reset them as needed. + */ - editor_mixer_button (_("editor\nmixer")), + vertical_adjustment (0.0, 0.0, 10.0, 400.0), + horizontal_adjustment (0.0, 0.0, 20.0, 1200.0), + + /* tool bar related */ selection_start_clock (X_("SelectionStartClock"), true), selection_end_clock (X_("SelectionEndClock"), true), @@ -222,15 +243,6 @@ Editor::Editor (AudioEngine& eng) PublicEditor::_instance = this; - init_colormap (); - - check_pixmap = gdk_pixmap_colormap_create_from_xpm_d (NULL, - gtk_widget_get_colormap (GTK_WIDGET(edit_group_list.gobj())), - &check_mask, NULL, (gchar **) check_xpm); - empty_pixmap = gdk_pixmap_colormap_create_from_xpm_d (NULL, - gtk_widget_get_colormap (GTK_WIDGET(edit_group_list.gobj())), - &empty_mask, NULL, (gchar **) empty_xpm); - session = 0; selection = new Selection; @@ -263,6 +275,11 @@ Editor::Editor (AudioEngine& eng) canvas_height = 0; autoscroll_timeout_tag = -1; interthread_progress_window = 0; + +#ifdef FFT_ANALYSIS + analysis_window = 0; +#endif + current_interthread_info = 0; _show_measures = true; _show_waveforms = true; @@ -272,31 +289,32 @@ Editor::Editor (AudioEngine& eng) show_gain_after_trim = false; no_zoom_repos_update = false; ignore_route_list_reorder = false; + no_route_list_redisplay = false; verbose_cursor_on = true; route_removal = false; track_spacing = 0; show_automatic_regions_in_region_list = true; + region_list_sort_type = (Editing::RegionListSortType) 0; have_pending_keyboard_selection = false; _follow_playhead = true; _xfade_visibility = true; editor_ruler_menu = 0; no_ruler_shown_update = false; + edit_hscroll_dragging = false; edit_group_list_menu = 0; route_list_menu = 0; region_list_menu = 0; marker_menu = 0; + range_marker_menu = 0; marker_menu_item = 0; tm_marker_menu = 0; transport_marker_menu = 0; new_transport_marker_menu = 0; editor_mixer_strip_width = Wide; repos_zoom_queued = false; - import_audio_item = 0; - embed_audio_item = 0; region_edit_menu_split_item = 0; temp_location = 0; region_edit_menu_split_multichannel_item = 0; - edit_hscroll_dragging = false; leftmost_frame = 0; ignore_mouse_mode_toggle = false; current_stepping_trackview = 0; @@ -305,9 +323,11 @@ Editor::Editor (AudioEngine& eng) clear_entered_track = false; _new_regionviews_show_envelope = false; current_timestretch = 0; - + in_edit_group_row_change = false; + last_canvas_frame = 0; edit_cursor = 0; playhead_cursor = 0; + button_release_can_deselect = true; location_marker_color = color_map[cLocationMarker]; location_range_color = color_map[cLocationRange]; @@ -318,52 +338,43 @@ Editor::Editor (AudioEngine& eng) range_marker_drag_rect = 0; marker_drag_line = 0; - mouse_mode = MouseZoom; /* force change in next call */ set_mouse_mode (MouseObject, true); frames_per_unit = 2048; /* too early to use set_frames_per_unit */ + reset_hscrollbar_stepping (); + zoom_focus = ZoomFocusLeft; zoom_range_clock.ValueChanged.connect (mem_fun(*this, &Editor::zoom_adjustment_changed)); initialize_rulers (); initialize_canvas (); - track_canvas_scroller.add (track_canvas); - track_canvas_scroller.set_policy (Gtk::POLICY_NEVER, Gtk::POLICY_NEVER); - track_canvas_scroller.set_name ("TrackCanvasScroller"); - - track_canvas_scroller.get_vadjustment()->signal_value_changed().connect (mem_fun(*this, &Editor::tie_vertical_scrolling)); - track_canvas_scroller.get_vadjustment()->set_step_increment (10.0); - - track_canvas_scroller.get_hadjustment()->set_lower (0.0); - track_canvas_scroller.get_hadjustment()->set_upper (1200.0); - track_canvas_scroller.get_hadjustment()->set_step_increment (20.0); - track_canvas_scroller.get_hadjustment()->signal_value_changed().connect (mem_fun(*this, &Editor::canvas_horizontally_scrolled)); + edit_controls_vbox.set_spacing (0); + horizontal_adjustment.signal_value_changed().connect (mem_fun(*this, &Editor::canvas_horizontally_scrolled)); + vertical_adjustment.signal_value_changed().connect (mem_fun(*this, &Editor::tie_vertical_scrolling)); - edit_vscrollbar.set_adjustment(*track_canvas_scroller.get_vadjustment()); - edit_hscrollbar.set_adjustment(*track_canvas_scroller.get_hadjustment()); + track_canvas.set_hadjustment (horizontal_adjustment); + track_canvas.set_vadjustment (vertical_adjustment); + time_canvas.set_hadjustment (horizontal_adjustment); - edit_hscrollbar.signal_button_press_event().connect (mem_fun(*this, &Editor::hscroll_slider_button_press)); - edit_hscrollbar.signal_button_release_event().connect (mem_fun(*this, &Editor::hscroll_slider_button_release)); - edit_hscrollbar.signal_size_allocate().connect (mem_fun(*this, &Editor::hscroll_slider_allocate)); + track_canvas.signal_map_event().connect (mem_fun (*this, &Editor::track_canvas_map_handler)); + time_canvas.signal_map_event().connect (mem_fun (*this, &Editor::time_canvas_map_handler)); - time_canvas_scroller.add (time_canvas); - time_canvas_scroller.set_policy (Gtk::POLICY_NEVER, Gtk::POLICY_NEVER); - time_canvas_scroller.set_hadjustment (*track_canvas_scroller.get_hadjustment()); - time_canvas_scroller.set_name ("TimeCanvasScroller"); - - edit_controls_vbox.set_spacing (track_spacing); - edit_controls_hbox.pack_start (edit_controls_vbox, true, true); - edit_controls_scroller.add (edit_controls_hbox); - edit_controls_scroller.set_name ("EditControlsBase"); - edit_controls_scroller.set_policy (Gtk::POLICY_NEVER, Gtk::POLICY_NEVER); + controls_layout.add (edit_controls_vbox); + controls_layout.set_name ("EditControlsBase"); + controls_layout.add_events (Gdk::SCROLL_MASK); + controls_layout.signal_scroll_event().connect (mem_fun(*this, &Editor::control_layout_scroll), false); + + controls_layout.add_events (Gdk::BUTTON_PRESS_MASK|Gdk::BUTTON_RELEASE_MASK|Gdk::ENTER_NOTIFY_MASK|Gdk::LEAVE_NOTIFY_MASK); + controls_layout.signal_button_release_event().connect (mem_fun(*this, &Editor::edit_controls_button_release)); + controls_layout.signal_size_request().connect (mem_fun (*this, &Editor::controls_layout_size_request)); - Viewport* viewport = static_cast (edit_controls_scroller.get_child()); + edit_vscrollbar.set_adjustment (vertical_adjustment); + edit_hscrollbar.set_adjustment (horizontal_adjustment); - viewport->set_shadow_type (Gtk::SHADOW_NONE); - viewport->set_name ("EditControlsBase"); - viewport->add_events (Gdk::BUTTON_PRESS_MASK|Gdk::BUTTON_RELEASE_MASK|Gdk::ENTER_NOTIFY_MASK|Gdk::LEAVE_NOTIFY_MASK); - viewport->signal_button_release_event().connect (mem_fun(*this, &Editor::edit_controls_button_release)); + edit_hscrollbar.signal_button_press_event().connect (mem_fun(*this, &Editor::hscrollbar_button_press)); + edit_hscrollbar.signal_button_release_event().connect (mem_fun(*this, &Editor::hscrollbar_button_release)); + edit_hscrollbar.signal_size_allocate().connect (mem_fun(*this, &Editor::hscrollbar_allocate)); build_cursors (); setup_toolbar (); @@ -374,7 +385,7 @@ Editor::Editor (AudioEngine& eng) time_canvas_vbox.pack_start (*smpte_ruler, false, false); time_canvas_vbox.pack_start (*frames_ruler, false, false); time_canvas_vbox.pack_start (*bbt_ruler, false, false); - time_canvas_vbox.pack_start (time_canvas_scroller, true, true); + time_canvas_vbox.pack_start (time_canvas, true, true); time_canvas_vbox.set_size_request (-1, (int)(timebar_height * visible_timebars)); bbt_label.set_name ("EditorTimeButton"); @@ -432,249 +443,258 @@ Editor::Editor (AudioEngine& eng) for the canvas areas. */ - track_canvas_event_box.add (track_canvas_scroller); + track_canvas_event_box.add (track_canvas); time_canvas_event_box.add (time_canvas_vbox); time_canvas_event_box.set_events (Gdk::BUTTON_PRESS_MASK|Gdk::BUTTON_RELEASE_MASK|Gdk::POINTER_MOTION_MASK); - edit_packer.set_col_spacings (0); edit_packer.set_row_spacings (0); edit_packer.set_homogeneous (false); + edit_packer.set_border_width (0); edit_packer.set_name ("EditorWindow"); + + edit_packer.attach (edit_vscrollbar, 0, 1, 1, 3, FILL, FILL|EXPAND, 0, 0); -// edit_packer.attach (edit_hscroll_left_arrow_event, 0, 1, 0, 1, Gtk::FILL, 0, 0, 0); -// edit_packer.attach (edit_hscroll_slider, 1, 2, 0, 1, Gtk::FILL|Gtk::EXPAND, 0, 0, 0); -// edit_packer.attach (edit_hscroll_right_arrow_event, 2, 3, 0, 1, Gtk::FILL, 0, 0, 0); - edit_packer.attach (edit_hscrollbar, 1, 2, 0, 1, FILL|EXPAND, FILL, 0, 0); - - edit_packer.attach (time_button_event_box, 0, 1, 1, 2, FILL, FILL, 0, 0); - edit_packer.attach (time_canvas_event_box, 1, 2, 1, 2, FILL|EXPAND, FILL, 0, 0); + edit_packer.attach (time_button_event_box, 1, 2, 0, 1, FILL, FILL, 0, 0); + edit_packer.attach (time_canvas_event_box, 2, 3, 0, 1, FILL|EXPAND, FILL, 0, 0); - edit_packer.attach (edit_controls_scroller, 0, 1, 2, 3, FILL, FILL|EXPAND, 0, 0); - edit_packer.attach (track_canvas_event_box, 1, 2, 2, 3, FILL|EXPAND, FILL|EXPAND, 0, 0); - edit_packer.attach (edit_vscrollbar, 2, 3, 2, 3, FILL, FILL|EXPAND, 0, 0); + edit_packer.attach (controls_layout, 1, 2, 1, 2, FILL, FILL|EXPAND, 0, 0); + edit_packer.attach (track_canvas_event_box, 2, 3, 1, 2, FILL|EXPAND, FILL|EXPAND, 0, 0); - edit_frame.set_name ("BaseFrame"); - edit_frame.set_shadow_type (SHADOW_IN); - edit_frame.add (edit_packer); + edit_packer.attach (edit_hscrollbar, 2, 3, 2, 3, FILL|EXPAND, FILL, 0, 0); zoom_in_button.set_name ("EditorTimeButton"); zoom_out_button.set_name ("EditorTimeButton"); ARDOUR_UI::instance()->tooltips().set_tip (zoom_in_button, _("Zoom in")); ARDOUR_UI::instance()->tooltips().set_tip (zoom_out_button, _("Zoom out")); -// zoom_onetoone_button.set_name ("EditorTimeButton"); zoom_out_full_button.set_name ("EditorTimeButton"); -// ARDOUR_UI::instance()->tooltips().set_tip (zoom_onetoone_button, _("Zoom in 1:1")); ARDOUR_UI::instance()->tooltips().set_tip (zoom_out_full_button, _("Zoom to session")); - zoom_in_button.add (*(manage (new Gtk::Image (Gdk::Pixbuf::create_from_xpm_data(zoom_in_button_xpm))))); - zoom_out_button.add (*(manage (new Gtk::Image (Gdk::Pixbuf::create_from_xpm_data(zoom_out_button_xpm))))); - zoom_out_full_button.add (*(manage (new Gtk::Image (Gdk::Pixbuf::create_from_xpm_data(zoom_out_full_button_xpm))))); -// zoom_onetoone_button.add (*(manage (new Gtk::Image (zoom_onetoone_button_xpm)))); - + zoom_in_button.add (*(manage (new Image (Stock::ZOOM_IN, ICON_SIZE_BUTTON)))); + zoom_out_button.add (*(manage (new Image (Stock::ZOOM_OUT, ICON_SIZE_BUTTON)))); + zoom_out_full_button.add (*(manage (new Image (Stock::ZOOM_FIT, ICON_SIZE_BUTTON)))); zoom_in_button.signal_clicked().connect (bind (mem_fun(*this, &Editor::temporal_zoom_step), false)); zoom_out_button.signal_clicked().connect (bind (mem_fun(*this, &Editor::temporal_zoom_step), true)); zoom_out_full_button.signal_clicked().connect (mem_fun(*this, &Editor::temporal_zoom_session)); -// zoom_onetoone_button.signal_clicked().connect (bind (mem_fun(*this, &Editor::temporal_zoom), 1.0)); zoom_indicator_box.pack_start (zoom_out_button, false, false); zoom_indicator_box.pack_start (zoom_in_button, false, false); zoom_indicator_box.pack_start (zoom_range_clock, false, false); -// zoom_indicator_box.pack_start (zoom_onetoone_button, false, false); zoom_indicator_box.pack_start (zoom_out_full_button, false, false); zoom_indicator_label.set_text (_("Zoom Span")); zoom_indicator_label.set_name ("ToolBarLabel"); - zoom_indicator_vbox.set_spacing (3); zoom_indicator_vbox.set_border_width (3); zoom_indicator_vbox.pack_start (zoom_indicator_label, false, false); zoom_indicator_vbox.pack_start (zoom_indicator_box, false, false); - bottom_hbox.set_border_width (3); bottom_hbox.set_spacing (3); route_display_model = ListStore::create(route_display_columns); - route_list.set_model (route_display_model); - route_list.append_column (_("Tracks"), route_display_columns.text); - route_list.set_name ("TrackListDisplay"); - route_list.get_selection()->set_mode (Gtk::SELECTION_MULTIPLE); - route_list.set_reorderable (true); + route_list_display.set_model (route_display_model); + route_list_display.append_column (_("Visible"), route_display_columns.visible); + route_list_display.append_column (_("Name"), route_display_columns.text); + route_list_display.get_column (0)->set_data (X_("colnum"), GUINT_TO_POINTER(0)); + route_list_display.get_column (1)->set_data (X_("colnum"), GUINT_TO_POINTER(1)); + route_list_display.set_headers_visible (true); + route_list_display.set_name ("TrackListDisplay"); + route_list_display.get_selection()->set_mode (SELECTION_NONE); + route_list_display.set_reorderable (true); + route_list_display.set_size_request (100,-1); + + CellRendererToggle* route_list_visible_cell = dynamic_cast(route_list_display.get_column_cell_renderer (0)); + route_list_visible_cell->property_activatable() = true; + route_list_visible_cell->property_radio() = false; - route_list.set_size_request (75,-1); - route_list.set_headers_visible (true); - route_list.set_headers_clickable (true); + route_display_model->signal_row_deleted().connect (mem_fun (*this, &Editor::route_list_delete)); + route_display_model->signal_row_changed().connect (mem_fun (*this, &Editor::route_list_change)); - // GTK2FIX - // route_list.signal_rows_reordered().connect (mem_fun (*this, &Editor::queue_route_list_reordered)); + route_list_display.signal_button_press_event().connect (mem_fun (*this, &Editor::route_list_display_button_press), false); - // GTK2FIX - // route_display_model->set_sort_func (0, mem_fun (*this, &Editor::route_list_compare_func)); + route_list_scroller.add (route_list_display); + route_list_scroller.set_policy (POLICY_NEVER, POLICY_AUTOMATIC); - // GTK2FIX - //route_list.set_shadow_type (Gtk::SHADOW_IN); + group_model = ListStore::create(group_columns); + edit_group_display.set_model (group_model); + edit_group_display.append_column (_("Name"), group_columns.text); + edit_group_display.append_column (_("Active"), group_columns.is_active); + edit_group_display.append_column (_("Visible"), group_columns.is_visible); + edit_group_display.get_column (0)->set_data (X_("colnum"), GUINT_TO_POINTER(0)); + edit_group_display.get_column (1)->set_data (X_("colnum"), GUINT_TO_POINTER(1)); + edit_group_display.get_column (2)->set_data (X_("colnum"), GUINT_TO_POINTER(2)); + edit_group_display.get_column (0)->set_expand (true); + edit_group_display.get_column (1)->set_expand (false); + edit_group_display.get_column (2)->set_expand (false); + edit_group_display.set_headers_visible (true); - route_list_scroller.add (route_list); - route_list_scroller.set_policy (Gtk::POLICY_NEVER, Gtk::POLICY_AUTOMATIC); + /* name is directly editable */ - route_list.get_selection()->signal_changed().connect (mem_fun (*this, &Editor::route_display_selection_changed)); - route_list.signal_columns_changed().connect (mem_fun(*this, &Editor::route_list_column_click)); + CellRendererText* name_cell = dynamic_cast(edit_group_display.get_column_cell_renderer (0)); + name_cell->property_editable() = true; + name_cell->signal_edited().connect (mem_fun (*this, &Editor::edit_group_name_edit)); - edit_group_list_button_label.set_text (_("Edit Groups")); - edit_group_list_button_label.set_name ("EditGroupTitleButton"); - edit_group_list_button.add (edit_group_list_button_label); - edit_group_list_button.set_name ("EditGroupTitleButton"); + /* use checkbox for the active + visible columns */ - group_model = ListStore::create(group_columns); - edit_group_list.set_model (group_model); - edit_group_list.append_column (_("active"), group_columns.is_active); - edit_group_list.append_column (_("groupname"), group_columns.text); - edit_group_list.get_column (0)->set_data (X_("colnum"), GUINT_TO_POINTER(0)); - edit_group_list.get_column (0)->set_data (X_("colnum"), GUINT_TO_POINTER(1)); - - /* use checkbox for the active column */ - - CellRendererToggle *active_cell = dynamic_cast(edit_group_list.get_column_cell_renderer (0)); - active_cell->set_property ("activatable", true); - active_cell->set_property ("radio", false); - - edit_group_list.set_name ("MixerGroupList"); - //edit_group_list.set_shadow_type (Gtk::SHADOW_IN); - route_list.set_headers_visible (false); - edit_group_list.set_reorderable (false); - edit_group_list.set_size_request (75, -1); - edit_group_list.columns_autosize (); - edit_group_list.get_selection()->set_mode (Gtk::SELECTION_MULTIPLE); - - edit_group_list_scroller.add (edit_group_list); - edit_group_list_scroller.set_policy (Gtk::POLICY_AUTOMATIC, Gtk::POLICY_AUTOMATIC); - - edit_group_list_button.signal_clicked().connect (mem_fun(*this, &Editor::edit_group_list_button_clicked)); - edit_group_list.signal_button_press_event().connect (mem_fun(*this, &Editor::edit_group_list_button_press_event)); - edit_group_list.get_selection()->signal_changed().connect (mem_fun(*this, &Editor::edit_group_selection_changed)); - - TreeModel::Row row = *(group_model->append()); - row[group_columns.is_active] = false; - row[group_columns.text] = (_("-all-")); - edit_group_list.get_selection()->select (row); -/* GTK2FIX is set_data(0) setting the is_active to false here? - list stupid_list; - - stupid_list.push_back ("*"); - stupid_list.push_back (_("-all-")); - - edit_group_list.rows().push_back (stupid_list); - edit_group_list.rows().back().set_data (0); - edit_group_list.rows().back().select(); - -*/ - edit_group_vbox.pack_start (edit_group_list_button, false, false); - edit_group_vbox.pack_start (edit_group_list_scroller, true, true); - - route_list_frame.set_name ("BaseFrame"); - route_list_frame.set_shadow_type (Gtk::SHADOW_IN); - route_list_frame.add (route_list_scroller); + CellRendererToggle* active_cell = dynamic_cast(edit_group_display.get_column_cell_renderer (1)); + active_cell->property_activatable() = true; + active_cell->property_radio() = false; + + active_cell = dynamic_cast(edit_group_display.get_column_cell_renderer (1)); + active_cell->property_activatable() = true; + active_cell->property_radio() = false; + + edit_group_display.set_name ("EditGroupList"); + + group_model->signal_row_changed().connect (mem_fun (*this, &Editor::edit_group_row_change)); + + edit_group_display.set_name ("EditGroupList"); + edit_group_display.get_selection()->set_mode (SELECTION_SINGLE); + edit_group_display.set_reorderable (false); + edit_group_display.set_rules_hint (true); + edit_group_display.set_size_request (75, -1); + + edit_group_display_scroller.add (edit_group_display); + edit_group_display_scroller.set_policy (POLICY_AUTOMATIC, POLICY_AUTOMATIC); + + edit_group_display.signal_button_press_event().connect (mem_fun(*this, &Editor::edit_group_list_button_press_event), false); + + VBox* edit_group_display_packer = manage (new VBox()); + HButtonBox* edit_group_display_button_box = manage (new HButtonBox()); + edit_group_display_button_box->set_homogeneous (true); + + Button* edit_group_add_button = manage (new Button ()); + Button* edit_group_remove_button = manage (new Button ()); + + Widget* w; + + w = manage (new Image (Stock::ADD, ICON_SIZE_BUTTON)); + w->show(); + edit_group_add_button->add (*w); - edit_group_list_frame.set_name ("BaseFrame"); - edit_group_list_frame.set_shadow_type (Gtk::SHADOW_IN); - edit_group_list_frame.add (edit_group_vbox); + w = manage (new Image (Stock::REMOVE, ICON_SIZE_BUTTON)); + w->show(); + edit_group_remove_button->add (*w); - route_group_vpane.add1 (route_list_frame); - route_group_vpane.add2 (edit_group_list_frame); + edit_group_add_button->signal_clicked().connect (mem_fun (*this, &Editor::new_edit_group)); + edit_group_remove_button->signal_clicked().connect (mem_fun (*this, &Editor::remove_selected_edit_group)); + + edit_group_display_button_box->pack_start (*edit_group_add_button); + edit_group_display_button_box->pack_start (*edit_group_remove_button); + + edit_group_display_packer->pack_start (edit_group_display_scroller, true, true); + edit_group_display_packer->pack_start (*edit_group_display_button_box, false, false); - list_vpacker.pack_start (route_group_vpane, true, true); + region_list_display.set_size_request (100, -1); + region_list_display.set_name ("RegionListDisplay"); region_list_model = TreeStore::create (region_list_columns); - region_list_sort_model = TreeModelSort::create (region_list_model); region_list_model->set_sort_func (0, mem_fun (*this, &Editor::region_list_sorter)); + region_list_model->set_sort_column (0, SORT_ASCENDING); - region_list_display.set_model (region_list_sort_model); + region_list_display.set_model (region_list_model); region_list_display.append_column (_("Regions"), region_list_columns.name); - region_list_display.set_reorderable (true); - region_list_display.set_size_request (100, -1); - region_list_display.set_data ("editor", this); - region_list_display.set_flags (Gtk::CAN_FOCUS); - region_list_display.set_name ("RegionListDisplay"); + region_list_display.set_headers_visible (false); + region_list_display.set_hover_expand (true); - region_list_scroller.add (region_list_display); - region_list_scroller.set_policy (Gtk::POLICY_NEVER, Gtk::POLICY_AUTOMATIC); + region_list_display.get_selection()->set_select_function (mem_fun (*this, &Editor::region_list_selection_filter)); + + TreeViewColumn* tv_col = region_list_display.get_column(0); + CellRendererText* renderer = dynamic_cast(region_list_display.get_column_cell_renderer (0)); + tv_col->add_attribute(renderer->property_text(), region_list_columns.name); + tv_col->add_attribute(renderer->property_foreground_gdk(), region_list_columns.color_); + + region_list_display.get_selection()->set_mode (SELECTION_MULTIPLE); + region_list_display.add_object_drag (region_list_columns.region.index(), "regions"); - list region_list_target_table; + /* setup DnD handling */ + + list region_list_target_table; - region_list_target_table.push_back (TargetEntry ("STRING")); region_list_target_table.push_back (TargetEntry ("text/plain")); region_list_target_table.push_back (TargetEntry ("text/uri-list")); region_list_target_table.push_back (TargetEntry ("application/x-rootwin-drop")); + + region_list_display.add_drop_targets (region_list_target_table); + region_list_display.signal_drag_data_received().connect (mem_fun(*this, &Editor::region_list_display_drag_data_received)); - // GTK2FIX - // region_list_display.drag_dest_set (region_list_target_table, DEST_DEFAULT_ALL, GdkDragAction (Gdk::ACTION_COPY|Gdk::ACTION_MOVE)); - // region_list_display.signal_drag_data_received().connect (mem_fun(*this, &Editor::region_list_display_drag_data_received)); + region_list_scroller.add (region_list_display); + region_list_scroller.set_policy (POLICY_NEVER, POLICY_AUTOMATIC); region_list_display.signal_key_press_event().connect (mem_fun(*this, &Editor::region_list_display_key_press)); region_list_display.signal_key_release_event().connect (mem_fun(*this, &Editor::region_list_display_key_release)); - region_list_display.signal_button_press_event().connect (mem_fun(*this, &Editor::region_list_display_button_press)); + region_list_display.signal_button_press_event().connect (mem_fun(*this, &Editor::region_list_display_button_press), false); region_list_display.signal_button_release_event().connect (mem_fun(*this, &Editor::region_list_display_button_release)); region_list_display.get_selection()->signal_changed().connect (mem_fun(*this, &Editor::region_list_selection_changed)); - // GTK2FIX - //region_list_display.unselect_row.connect (mem_fun(*this, &Editor::region_list_display_unselected)); - //region_list_display.signal_columns_changed().connect (mem_fun(*this, &Editor::region_list_column_click)); + // region_list_display.signal_popup_menu().connect (bind (mem_fun (*this, &Editor::show_region_list_display_context_menu), 1, 0)); named_selection_scroller.add (named_selection_display); - named_selection_scroller.set_policy (Gtk::POLICY_NEVER, Gtk::POLICY_AUTOMATIC); + named_selection_scroller.set_policy (POLICY_NEVER, POLICY_AUTOMATIC); named_selection_model = TreeStore::create (named_selection_columns); named_selection_display.set_model (named_selection_model); + named_selection_display.append_column (_("Chunks"), named_selection_columns.text); + named_selection_display.set_headers_visible (false); + named_selection_display.set_size_request (100, -1); named_selection_display.set_name ("RegionListDisplay"); + + named_selection_display.get_selection()->set_mode (SELECTION_SINGLE); named_selection_display.set_size_request (100, -1); - named_selection_display.set_headers_visible (true); - named_selection_display.set_headers_clickable (true); - named_selection_display.get_selection()->set_mode (Gtk::SELECTION_SINGLE); - named_selection_display.signal_button_press_event().connect (mem_fun(*this, &Editor::named_selection_display_button_press)); + named_selection_display.signal_button_press_event().connect (mem_fun(*this, &Editor::named_selection_display_button_press), false); named_selection_display.get_selection()->signal_changed().connect (mem_fun (*this, &Editor::named_selection_display_selection_changed)); - region_selection_vpane.pack1 (region_list_scroller, true, true); - region_selection_vpane.pack2 (named_selection_scroller, true, true); - - canvas_region_list_pane.pack1 (edit_frame, true, true); - canvas_region_list_pane.pack2 (region_selection_vpane, true, true); - - track_list_canvas_pane.signal_size_allocate().connect_notify (bind (mem_fun(*this, &Editor::pane_allocation_handler), - static_cast (&track_list_canvas_pane))); - canvas_region_list_pane.signal_size_allocate().connect_notify (bind (mem_fun(*this, &Editor::pane_allocation_handler), - static_cast (&canvas_region_list_pane))); - route_group_vpane.signal_size_allocate().connect_notify (bind (mem_fun(*this, &Editor::pane_allocation_handler), - static_cast (&route_group_vpane))); - region_selection_vpane.signal_size_allocate().connect_notify (bind (mem_fun(*this, &Editor::pane_allocation_handler), - static_cast (®ion_selection_vpane))); + /* SNAPSHOTS */ + + snapshot_display_model = ListStore::create (snapshot_display_columns); + snapshot_display.set_model (snapshot_display_model); + snapshot_display.append_column (X_("snapshot"), snapshot_display_columns.visible_name); + snapshot_display.set_name ("SnapshotDisplayList"); + snapshot_display.set_size_request (75, -1); + snapshot_display.set_headers_visible (false); + snapshot_display.set_reorderable (false); + snapshot_display_scroller.add (snapshot_display); + snapshot_display_scroller.set_policy (Gtk::POLICY_NEVER, Gtk::POLICY_AUTOMATIC); + + snapshot_display.get_selection()->signal_changed().connect (mem_fun(*this, &Editor::snapshot_display_selection_changed)); + snapshot_display.signal_button_press_event().connect (mem_fun (*this, &Editor::snapshot_display_button_press), false); + + Gtk::Label* nlabel; + + nlabel = manage (new Label (_("Regions"))); + nlabel->set_angle (-90); + the_notebook.append_page (region_list_scroller, *nlabel); + nlabel = manage (new Label (_("Tracks/Busses"))); + nlabel->set_angle (-90); + the_notebook.append_page (route_list_scroller, *nlabel); + nlabel = manage (new Label (_("Snapshots"))); + nlabel->set_angle (-90); + the_notebook.append_page (snapshot_display_scroller, *nlabel); + nlabel = manage (new Label (_("Edit Groups"))); + nlabel->set_angle (-90); + the_notebook.append_page (*edit_group_display_packer, *nlabel); + nlabel = manage (new Label (_("Chunks"))); + nlabel->set_angle (-90); + the_notebook.append_page (named_selection_scroller, *nlabel); + + the_notebook.set_show_tabs (true); + the_notebook.set_scrollable (true); + the_notebook.popup_enable (); + the_notebook.set_tab_pos (Gtk::POS_RIGHT); + + edit_pane.pack1 (edit_packer, true, true); + edit_pane.pack2 (the_notebook, false, true); - track_list_canvas_pane.pack1 (list_vpacker, true, true); - track_list_canvas_pane.pack2 (canvas_region_list_pane, true, true); - - /* provide special pane-handle event handling for easy "hide" action */ - - /* 0: collapse to show left/upper child - 1: collapse to show right/lower child - */ - - route_group_vpane.set_data ("collapse-direction", (gpointer) 0); - region_selection_vpane.set_data ("collapse-direction", (gpointer) 0); - canvas_region_list_pane.set_data ("collapse-direction", (gpointer) 0); - track_list_canvas_pane.set_data ("collapse-direction", (gpointer) 1); - - route_group_vpane.signal_button_release_event().connect (bind (sigc::ptr_fun (pane_handler), static_cast (&route_group_vpane))); - region_selection_vpane.signal_button_release_event().connect (bind (sigc::ptr_fun (pane_handler), static_cast (®ion_selection_vpane))); - canvas_region_list_pane.signal_button_release_event().connect (bind (sigc::ptr_fun (pane_handler), static_cast (&canvas_region_list_pane))); - track_list_canvas_pane.signal_button_release_event().connect (bind (sigc::ptr_fun (pane_handler), static_cast (&track_list_canvas_pane))); + edit_pane.signal_size_allocate().connect_notify (bind (mem_fun(*this, &Editor::pane_allocation_handler), static_cast (&edit_pane))); top_hbox.pack_start (toolbar_frame, true, true); HBox *hbox = manage (new HBox); - hbox->pack_start (track_list_canvas_pane, true, true); + hbox->pack_start (edit_pane, true, true); global_vpacker.pack_start (top_hbox, false, false); global_vpacker.pack_start (*hbox, true, true); @@ -682,8 +702,13 @@ Editor::Editor (AudioEngine& eng) global_hpacker.pack_start (global_vpacker, true, true); set_name ("EditorWindow"); + add_accel_group (ActionManager::ui_manager->get_accel_group()); vpacker.pack_end (global_hpacker, true, true); + + /* register actions now so that set_state() can find them and set toggles/checks etc */ + + register_actions (); XMLNode* node = ARDOUR_UI::instance()->editor_settings(); set_state (*node); @@ -695,8 +720,8 @@ Editor::Editor (AudioEngine& eng) /* nudge stuff */ - nudge_forward_button.add (*(manage (new Gtk::Image (Gdk::Pixbuf::create_from_xpm_data(right_arrow_xpm))))); - nudge_backward_button.add (*(manage (new Gtk::Image (Gdk::Pixbuf::create_from_xpm_data(left_arrow_xpm))))); + nudge_forward_button.add (*(manage (new Image (get_xpm("right_arrow.xpm"))))); + nudge_backward_button.add (*(manage (new Image (get_xpm("left_arrow.xpm"))))); ARDOUR_UI::instance()->tooltips().set_tip (nudge_forward_button, _("Nudge region/selection forwards")); ARDOUR_UI::instance()->tooltips().set_tip (nudge_backward_button, _("Nudge region/selection backwards")); @@ -715,6 +740,12 @@ Editor::Editor (AudioEngine& eng) signal_configure_event().connect (mem_fun (*ARDOUR_UI::instance(), &ARDOUR_UI::configure_handler)); signal_delete_event().connect (mem_fun (*ARDOUR_UI::instance(), &ARDOUR_UI::exit_on_main_window_close)); + /* allow external control surfaces/protocols to do various things */ + + ControlProtocol::ZoomToSession.connect (mem_fun (*this, &Editor::temporal_zoom_session)); + ControlProtocol::ZoomIn.connect (bind (mem_fun (*this, &Editor::temporal_zoom_step), false)); + ControlProtocol::ZoomOut.connect (bind (mem_fun (*this, &Editor::temporal_zoom_step), true)); + ControlProtocol::ScrollTimeline.connect (mem_fun (*this, &Editor::control_scroll)); constructed = true; instant_save (); } @@ -786,214 +817,12 @@ Editor::set_entered_track (TimeAxisView* tav) } } -gint -Editor::left_track_canvas (GdkEventCrossing *ev) -{ - set_entered_track (0); - set_entered_regionview (0); - return FALSE; -} - - -void -Editor::initialize_canvas () -{ - ArdourCanvas::init (); - - /* adjust sensitivity for "picking" items */ - - // GNOME_CANVAS(track_canvas)->close_enough = 2; - - track_canvas.signal_event().connect (bind (mem_fun (*this, &Editor::track_canvas_event), (ArdourCanvas::Item*) 0)); - track_canvas.set_name ("EditorMainCanvas"); - track_canvas.add_events (Gdk::POINTER_MOTION_HINT_MASK); - track_canvas.signal_leave_notify_event().connect (mem_fun(*this, &Editor::left_track_canvas)); - - /* set up drag-n-drop */ - vector target_table; - - target_table.push_back (TargetEntry ("STRING")); - target_table.push_back (TargetEntry ("text/plain")); - target_table.push_back (TargetEntry ("text/uri-list")); - target_table.push_back (TargetEntry ("application/x-rootwin-drop")); - - // GTK2FIX - // track_canvas.drag_dest_set (target_table, DEST_DEFAULT_ALL, GdkDragAction (Gdk::ACTION_COPY|Gdk::ACTION_MOVE)); - // track_canvas.signal_drag_data_received().connect (mem_fun(*this, &Editor::track_canvas_drag_data_received)); - - /* stuff for the verbose canvas cursor */ - - Pango::FontDescription font = get_font_for_style (N_("VerboseCanvasCursor")); - - verbose_canvas_cursor = new ArdourCanvas::Text (*track_canvas.root()); - verbose_canvas_cursor->set_property ("font_desc", font); - // GTK2FIX - // verbose_canvas_cursor->set_property ("anchor", GTK_ANCHOR_NW); - verbose_canvas_cursor->set_property ("fill_color_rgba", color_map[cVerboseCanvasCursor]); - - verbose_cursor_visible = false; - - /* a group to hold time (measure) lines */ - - time_line_group = new ArdourCanvas::Group (*track_canvas.root(), 0.0, 0.0); - cursor_group = new ArdourCanvas::Group (*track_canvas.root(), 0.0, 0.0); - - time_canvas.set_name ("EditorTimeCanvas"); - time_canvas.add_events (Gdk::POINTER_MOTION_HINT_MASK); - - meter_group = new ArdourCanvas::Group (*time_canvas.root(), 0.0, 0.0); - tempo_group = new ArdourCanvas::Group (*time_canvas.root(), 0.0, 0.0); - marker_group = new ArdourCanvas::Group (*time_canvas.root(), 0.0, timebar_height * 2.0); - range_marker_group = new ArdourCanvas::Group (*time_canvas.root(), 0.0, timebar_height * 3.0); - transport_marker_group = new ArdourCanvas::Group (*time_canvas.root(), 0.0, timebar_height * 4.0); - - tempo_bar = new ArdourCanvas::SimpleRect (*tempo_group, 0.0, 0.0, max_canvas_coordinate, timebar_height); - tempo_bar->set_property ("fill_color_rgba", color_map[cTempoBar]); - tempo_bar->set_property ("outline_pixels", 0); - - meter_bar = new ArdourCanvas::SimpleRect (*meter_group, 0.0, 0.0, max_canvas_coordinate, timebar_height); - meter_bar->set_property ("fill_color_rgba", color_map[cMeterBar]); - meter_bar->set_property ("outline_pixels",0); - - marker_bar = new ArdourCanvas::SimpleRect (*marker_group, 0.0, 0.0, max_canvas_coordinate, timebar_height); - marker_bar->set_property ("fill_color_rgba", color_map[cMarkerBar]); - marker_bar->set_property ("outline_pixels", 0); - - range_marker_bar = new ArdourCanvas::SimpleRect (*range_marker_group, 0.0, 0.0, max_canvas_coordinate, timebar_height); - range_marker_bar->set_property ("fill_color_rgba", color_map[cRangeMarkerBar]); - range_marker_bar->set_property ("outline_pixels", 0); - - transport_marker_bar = new ArdourCanvas::SimpleRect (*transport_marker_group, 0.0, 0.0, max_canvas_coordinate, timebar_height); - transport_marker_bar->set_property ("fill_color_rgba", color_map[cTransportMarkerBar]); - transport_marker_bar->set_property ("outline_pixels", 0); - - range_bar_drag_rect = new ArdourCanvas::SimpleRect (*range_marker_group, 0.0, 0.0, max_canvas_coordinate, timebar_height); - range_bar_drag_rect->set_property ("fill_color_rgba", color_map[cRangeDragBarRectFill]); - range_bar_drag_rect->set_property ("outline_color_rgba", color_map[cRangeDragBarRect]); - range_bar_drag_rect->set_property ("outline_pixels", 0); - range_bar_drag_rect->hide (); - - transport_bar_drag_rect = new ArdourCanvas::SimpleRect (*transport_marker_group, 0.0, 0.0, max_canvas_coordinate, timebar_height); - transport_bar_drag_rect ->set_property ("fill_color_rgba", color_map[cTransportDragRectFill]); - transport_bar_drag_rect->set_property ("outline_color_rgba", color_map[cTransportDragRect]); - transport_bar_drag_rect->set_property ("outline_pixels", 0); - transport_bar_drag_rect->hide (); - - marker_drag_line_points.push_back(Gnome::Art::Point(0.0, 0.0)); - marker_drag_line_points.push_back(Gnome::Art::Point(0.0, 0.0)); - - marker_drag_line = new ArdourCanvas::Line (*track_canvas.root()); - marker_drag_line->set_property ("width_pixels", 1); - marker_drag_line->set_property("fill_color_rgba", color_map[cMarkerDragLine]); - marker_drag_line->set_property("points", marker_drag_line_points); - marker_drag_line->hide(); - - range_marker_drag_rect = new ArdourCanvas::SimpleRect (*track_canvas.root(), 0.0, 0.0, 0.0, 0.0); - range_marker_drag_rect->set_property ("fill_color_rgba", color_map[cRangeDragRectFill]); - range_marker_drag_rect->set_property ("outline_color_rgba", color_map[cRangeDragRect]); - range_marker_drag_rect->hide (); - - transport_loop_range_rect = new ArdourCanvas::SimpleRect (*time_line_group, 0.0, 0.0, 0.0, 0.0); - transport_loop_range_rect->set_property ("fill_color_rgba", color_map[cTransportLoopRectFill]); - transport_loop_range_rect->set_property ("outline_color_rgba", color_map[cTransportLoopRect]); - transport_loop_range_rect->set_property ("outline_pixels", 1); - transport_loop_range_rect->hide(); - - transport_punch_range_rect = new ArdourCanvas::SimpleRect (*time_line_group, 0.0, 0.0, 0.0, 0.0); - transport_punch_range_rect->set_property ("fill_color_rgba", color_map[cTransportPunchRectFill]); - transport_punch_range_rect->set_property ("outline_color_rgba", color_map[cTransportPunchRect]); - transport_punch_range_rect->set_property ("outline_pixels", 0); - transport_punch_range_rect->hide(); - - transport_loop_range_rect->lower_to_bottom (); // loop on the bottom - - transport_punchin_line = new ArdourCanvas::SimpleLine (*time_line_group); - transport_punchin_line->set_property ("x1", 0.0); - transport_punchin_line->set_property ("y1", 0.0); - transport_punchin_line->set_property ("x2", 0.0); - transport_punchin_line->set_property ("y2", 0.0); - transport_punchin_line->property_color_rgba().set_value (color_map[cPunchInLine]); - transport_punchin_line->hide (); - - transport_punchout_line = new ArdourCanvas::SimpleLine (*time_line_group); - transport_punchout_line->set_property ("x1", 0.0); - transport_punchout_line->set_property ("y1", 0.0); - transport_punchout_line->set_property ("x2", 0.0); - transport_punchout_line->set_property ("y2", 0.0); - transport_punchout_line->property_color_rgba().set_value (color_map[cPunchOutLine]); - transport_punchout_line->hide(); - - // used to show zoom mode active zooming - zoom_rect = new ArdourCanvas::SimpleRect (*track_canvas.root(), 0.0, 0.0, 0.0, 0.0); - zoom_rect->set_property ("fill_color_rgba", color_map[cZoomRectFill]); - zoom_rect->set_property ("outline_color_rgba", color_map[cZoomRect]); - zoom_rect->set_property ("outline_pixels", 1); - zoom_rect->hide(); - - zoom_rect->signal_event().connect (bind (mem_fun (*this, &Editor::canvas_zoom_rect_event), (ArdourCanvas::Item*) 0)); - - // used as rubberband rect - rubberband_rect = new ArdourCanvas::SimpleRect (*track_canvas.root(), 0.0, 0.0, 0.0, 0.0); - rubberband_rect->set_property ("outline_color_rgba", color_map[cRubberBandRect]); - rubberband_rect->set_property ("fill_color_rgba", (guint32) color_map[cRubberBandRectFill]); - rubberband_rect->set_property ("outline_pixels", 1); - rubberband_rect->hide(); - - tempo_bar->signal_event().connect (bind (mem_fun (*this, &Editor::canvas_tempo_bar_event), tempo_bar)); - meter_bar->signal_event().connect (bind (mem_fun (*this, &Editor::canvas_meter_bar_event), meter_bar)); - marker_bar->signal_event().connect (bind (mem_fun (*this, &Editor::canvas_marker_bar_event), marker_bar)); - range_marker_bar->signal_event().connect (bind (mem_fun (*this, &Editor::canvas_range_marker_bar_event), range_marker_bar)); - transport_marker_bar->signal_event().connect (bind (mem_fun (*this, &Editor::canvas_transport_marker_bar_event), transport_marker_bar)); - - /* separator lines */ - - tempo_line_points.push_back(Gnome::Art::Point(0, timebar_height)); - tempo_line_points.push_back(Gnome::Art::Point(max_canvas_coordinate, timebar_height)); - - tempo_line = new ArdourCanvas::Line (*tempo_group, tempo_line_points); - tempo_line->set_property ("width_pixels", 0); - tempo_line->property_fill_color().set_value (0);; - - meter_line_points.push_back(Gnome::Art::Point (0, timebar_height)); - meter_line_points.push_back(Gnome::Art::Point(max_canvas_coordinate, timebar_height)); - - meter_line = new ArdourCanvas::Line (*meter_group, meter_line_points); - meter_line->set_property ("width_pixels", 0); - meter_line->property_fill_color().set_value (0);; - - marker_line_points.push_back(Gnome::Art::Point (0, timebar_height)); - marker_line_points.push_back(Gnome::Art::Point(max_canvas_coordinate, timebar_height)); - - marker_line = new ArdourCanvas::Line (*marker_group, marker_line_points); - marker_line->set_property ("width_pixels", 0); - marker_line->property_fill_color().set_value (0);; - - range_marker_line = new ArdourCanvas::Line (*range_marker_group, marker_line_points); - range_marker_line->set_property ("width_pixels", 0); - range_marker_line->property_fill_color().set_value (0);; - - transport_marker_line = new ArdourCanvas::Line (*transport_marker_group, marker_line_points); - transport_marker_line->set_property ("width_pixels", 0); - transport_marker_line->property_fill_color().set_value (0);; - - ZoomChanged.connect (bind (mem_fun(*this, &Editor::update_loop_range_view), false)); - ZoomChanged.connect (bind (mem_fun(*this, &Editor::update_punch_range_view), false)); - - double time_height = timebar_height * 5; - double time_width = FLT_MAX/frames_per_unit; - time_canvas.set_scroll_region(0.0, 0.0, time_width, time_height); - - edit_cursor = new Cursor (*this, "blue", &Editor::canvas_edit_cursor_event); - playhead_cursor = new Cursor (*this, "red", &Editor::canvas_playhead_cursor_event); - - track_canvas.signal_size_allocate().connect (mem_fun(*this, &Editor::track_canvas_allocate)); -} - void Editor::show_window () { show_all (); - + present (); + /* now reset all audio_time_axis heights, because widgets might need to be re-hidden */ @@ -1009,9 +838,8 @@ Editor::show_window () void Editor::tie_vertical_scrolling () { - edit_controls_scroller.get_vadjustment()->set_value (track_canvas_scroller.get_vadjustment()->get_value()); - - float y1 = track_canvas_scroller.get_vadjustment()->get_value(); + double y1 = vertical_adjustment.get_value(); + controls_layout.get_vadjustment()->set_value (y1); playhead_cursor->set_y_axis(y1); edit_cursor->set_y_axis(y1); } @@ -1031,7 +859,7 @@ Editor::set_frames_per_unit (double fpu) // convert fpu to frame count - frames = (jack_nframes_t) (fpu * canvas_width); + frames = (jack_nframes_t) floor (fpu * canvas_width); /* don't allow zooms that fit more than the maximum number of frames into an 800 pixel wide space. @@ -1051,25 +879,29 @@ Editor::set_frames_per_unit (double fpu) which will do the same updates. */ - if (session) { - track_canvas_scroller.get_hadjustment()->set_upper (session->current_end_frame() / frames_per_unit); - } - if (!no_zoom_repos_update) { - track_canvas_scroller.get_hadjustment()->set_value (leftmost_frame/frames_per_unit); - update_hscroller (); + horizontal_adjustment.set_value (leftmost_frame/frames_per_unit); update_fixed_rulers (); tempo_map_changed (Change (0)); } if (mouse_mode == MouseRange && selection->time.start () != selection->time.end_frame ()) { - for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) { - (*i)->reshow_selection (selection->time); + if (!selection->tracks.empty()) { + for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) { + (*i)->reshow_selection (selection->time); + } + } else { + for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) { + (*i)->reshow_selection (selection->time); + } } } ZoomChanged (); /* EMIT_SIGNAL */ + reset_hscrollbar_stepping (); + reset_scrolling_region (); + if (edit_cursor) edit_cursor->set_position (edit_cursor->current_frame); if (playhead_cursor) playhead_cursor->set_position (playhead_cursor->current_frame); @@ -1087,7 +919,7 @@ Editor::instant_save () if (session) { session->add_instant_xml(get_state(), session->path()); } else { - Config->add_instant_xml(get_state(), Config->get_user_ardour_path()); + Config->add_instant_xml(get_state(), get_user_ardour_path()); } } @@ -1096,12 +928,15 @@ Editor::reposition_x_origin (jack_nframes_t frame) { if (frame != leftmost_frame) { leftmost_frame = frame; - double pixel = frame_to_pixel (frame); - if (pixel >= track_canvas_scroller.get_hadjustment()->get_upper()) { - track_canvas_scroller.get_hadjustment()->set_upper (frame_to_pixel (frame + (current_page_frames()))); + + jack_nframes_t rightmost_frame = leftmost_frame + current_page_frames (); + + if (rightmost_frame > last_canvas_frame) { + last_canvas_frame = rightmost_frame; + reset_scrolling_region (); } - track_canvas_scroller.get_hadjustment()->set_value (frame/frames_per_unit); - XOriginChanged (); /* EMIT_SIGNAL */ + + horizontal_adjustment.set_value (frame/frames_per_unit); } } @@ -1121,31 +956,71 @@ Editor::zoom_adjustment_changed () return; } - double fpu = (double) zoom_range_clock.current_duration() / (double) canvas_width; + double fpu = zoom_range_clock.current_duration() / canvas_width; if (fpu < 1.0) { fpu = 1.0; - zoom_range_clock.set ((jack_nframes_t) (fpu * canvas_width)); - } - else if (fpu > session->current_end_frame() / (double) canvas_width) { - fpu = session->current_end_frame() / (double) canvas_width; - zoom_range_clock.set ((jack_nframes_t) (fpu * canvas_width)); + zoom_range_clock.set ((jack_nframes_t) floor (fpu * canvas_width)); + } else if (fpu > session->current_end_frame() / canvas_width) { + fpu = session->current_end_frame() / canvas_width; + zoom_range_clock.set ((jack_nframes_t) floor (fpu * canvas_width)); } temporal_zoom (fpu); } +void +Editor::control_scroll (float fraction) +{ + ENSURE_GUI_THREAD(bind (mem_fun (*this, &Editor::control_scroll), fraction)); + + if (!session) { + return; + } + + double step = fraction * current_page_frames(); + jack_nframes_t target; + + if ((fraction < 0.0f) && (session->transport_frame() < (jack_nframes_t) fabs(step))) { + target = 0; + } else if ((fraction > 0.0f) && (max_frames - session->transport_frame() < step)) { + target = (max_frames - (current_page_frames()*2)); // allow room for slop in where the PH is on the screen + } else { + target = (session->transport_frame() + (jack_nframes_t) floor ((fraction * current_page_frames()))); + } + + /* move visuals, we'll catch up with it later */ + + playhead_cursor->set_position (target); + + if (target > (current_page_frames() / 2)) { + /* try to center PH in window */ + reposition_x_origin (target - (current_page_frames()/2)); + } else { + reposition_x_origin (0); + } + + /* cancel the existing */ + + control_scroll_connection.disconnect (); + + /* add the next one */ + + control_scroll_connection = Glib::signal_timeout().connect (bind (mem_fun (*this, &Editor::deferred_control_scroll), target), 50); +} + +bool +Editor::deferred_control_scroll (jack_nframes_t target) +{ + session->request_locate (target); + return false; +} + void Editor::canvas_horizontally_scrolled () { - /* XXX note the potential loss of accuracy here caused by - adjustments being 32bit floats with only a 24 bit mantissa, - whereas jack_nframes_t is at least a 32 bit uint32_teger. - */ - - leftmost_frame = (jack_nframes_t) floor (track_canvas_scroller.get_hadjustment()->get_value() * frames_per_unit); - - update_hscroller (); + leftmost_frame = (jack_nframes_t) floor (horizontal_adjustment.get_value() * frames_per_unit); + update_fixed_rulers (); if (!edit_hscroll_dragging) { @@ -1159,7 +1034,7 @@ void Editor::reposition_and_zoom (jack_nframes_t frame, double nfpu) { if (!repos_zoom_queued) { - Glib::signal_idle().connect (bind (mem_fun(*this, &Editor::deferred_reposition_and_zoom), frame, nfpu)); + Glib::signal_idle().connect (bind (mem_fun(*this, &Editor::deferred_reposition_and_zoom), frame, nfpu)); repos_zoom_queued = true; } } @@ -1187,193 +1062,7 @@ void Editor::on_realize () { Window::on_realize (); - - /* Even though we're not using acceleration, we want the - labels to show up. - */ - - track_context_menu.accelerate (*this->get_toplevel()); - track_region_context_menu.accelerate (*this->get_toplevel()); - - Glib::RefPtr empty_pixmap = Gdk::Pixmap::create(get_window(), 1, 1, 1); - Glib::RefPtr empty_bitmap = Gdk::Pixmap::create(get_window(), 1, 1, 1); - Gdk::Color white ("#ffffff" ); - - null_cursor = new Gdk::Cursor(empty_pixmap, empty_bitmap, white, white, 0, 0); -} - -void -Editor::on_map () -{ - Window::on_map (); - - track_canvas_scroller.get_window()->set_cursor (*current_canvas_cursor); - time_canvas_scroller.get_window()->set_cursor (*timebar_cursor); -} - -void -Editor::track_canvas_allocate (Gtk::Allocation alloc) -{ - canvas_width = alloc.get_width(); - canvas_height = alloc.get_height(); - - if (session == 0 && !ARDOUR_UI::instance()->will_create_new_session_automatically()) { - - Pango::FontDescription font = get_font_for_style (N_("FirstActionMessage")); - - const char *txt1 = _("Start a new session\n"); - const char *txt2 = _("via Session menu"); - - /* this mess of code is here to find out how wide this text is and - position the message in the center of the editor window. there - are two lines, so we use the longer of the the lines to - compute width, and multiply the height by 2. - */ - - int pixel_height; - int pixel_width; - - /* this is a dummy widget that exists so that we can get the - style from the RC file. - */ - - Label foo (_(txt2)); - Glib::RefPtr layout; - foo.set_name ("NoSessionMessage"); - foo.ensure_style (); - - layout = foo.create_pango_layout (_(txt2)); - layout->set_font_description (font); - layout->get_pixel_size (pixel_width, pixel_height); - - if (first_action_message == 0) { - - char txt[strlen(txt1)+strlen(txt2)+1]; - - /* merge both lines */ - - strcpy (txt, _(txt1)); - strcat (txt, _(txt2)); - - first_action_message = new ArdourCanvas::Text (*track_canvas.root()); - first_action_message->set_property ("font_desc", font); - first_action_message->set_property ("fill_color_rgba", color_map[cFirstActionMessage]); - first_action_message->set_property ("x", (gdouble) (canvas_width - pixel_width) / 2.0); - first_action_message->set_property ("y", (gdouble) (canvas_height/2.0) - (2.0 * (pixel_height))); - first_action_message->set_property ("anchor", GTK_ANCHOR_NORTH_WEST); - first_action_message->set_property ("text", ustring (txt)); - - } else { - - /* center it */ - first_action_message->set_property ("x", (gdouble) (canvas_width - pixel_width) / 2.0), - first_action_message->set_property ("y", (gdouble) (canvas_height/2.0) - (2.0 * (pixel_height))); - } - } - - zoom_range_clock.set ((jack_nframes_t) (canvas_width * frames_per_unit)); - edit_cursor->set_position (edit_cursor->current_frame); - playhead_cursor->set_position (playhead_cursor->current_frame); - reset_scrolling_region (&alloc); - - Resized (); /* EMIT_SIGNAL */ -} - -void -Editor::reset_scrolling_region (Gtk::Allocation* alloc) -{ - guint32 last_canvas_unit; - double height; - guint32 canvas_alloc_height, canvas_alloc_width; - TrackViewList::iterator i; - static bool first_time = true; - - /* We need to make sure that the canvas always has its - scrolling region set to larger of: - - - the size allocated for it (within the container its packed in) - - the size required to see the entire session - - If we don't ensure at least the first of these, the canvas - does some wierd and in my view unnecessary stuff to center - itself within the allocated area, which causes bad, bad - results. - - XXX GnomeCanvas has fixed this, and has an option to - control the centering behaviour. - */ - - last_canvas_unit = (guint32) ceil ((float) max_frames / frames_per_unit); - - height = 0; - - if (session) { - for (i = track_views.begin(); i != track_views.end(); ++i) { - if ((*i)->control_parent) { - height += (*i)->effective_height; - height += track_spacing; - } - } - - if (height) { - height -= track_spacing; - } - } - - canvas_height = (guint32) height; - - if (alloc) { - canvas_alloc_height = alloc->get_height(); - canvas_alloc_width = alloc->get_width(); - } else { - canvas_alloc_height = track_canvas.get_height(); - canvas_alloc_width = track_canvas.get_width(); - } - - canvas_height = max (canvas_height, canvas_alloc_height); - track_canvas.set_scroll_region ( 0.0, 0.0, max (last_canvas_unit, canvas_alloc_width), canvas_height); - - if (edit_cursor) edit_cursor->set_length (canvas_alloc_height); - if (playhead_cursor) playhead_cursor->set_length (canvas_alloc_height); - - if (marker_drag_line) { - marker_drag_line_points.back().set_x(canvas_height); - // cerr << "set mlA points, nc = " << marker_drag_line_points.num_points << endl; - marker_drag_line->set_property("points", marker_drag_line_points); - } - if (range_marker_drag_rect) { - range_marker_drag_rect->set_property("y1", 0.0); - range_marker_drag_rect->set_property("y2", (double) canvas_height); - } - - if (transport_loop_range_rect) { - transport_loop_range_rect->set_property("y1", 0.0); - transport_loop_range_rect->set_property("y2", (double) canvas_height); - } - - if (transport_punch_range_rect) { - transport_punch_range_rect->set_property("y1", 0.0); - transport_punch_range_rect->set_property("y2", (double) canvas_height); - } - - if (transport_punchin_line) { - transport_punchin_line->set_property("y1", 0.0); - transport_punchin_line->set_property("y2", (double) canvas_height); - } - - if (transport_punchout_line) { - transport_punchout_line->set_property("y1", 0.0); - transport_punchout_line->set_property("y2", (double) canvas_height); - } - - update_fixed_rulers (); - - if (is_visible() && first_time) { - tempo_map_changed (Change (0)); - first_time = false; - } else { - redisplay_tempo (); - } + Realized (); } void @@ -1385,7 +1074,7 @@ Editor::queue_session_control_changed (Session::ControlType t) void Editor::session_control_changed (Session::ControlType t) { - // right now we're only tracking the loop and punch state + // right now we're only tracking some state here switch (t) { case Session::AutoLoop: @@ -1396,50 +1085,27 @@ Editor::session_control_changed (Session::ControlType t) update_punch_range_view (true); break; + case Session::LayeringModel: + update_layering_model (); + break; + default: break; } } void -Editor::fake_add_edit_group (RouteGroup *group) +Editor::start_scrolling () { - Gtkmm2ext::UI::instance()->call_slot (bind (mem_fun(*this, &Editor::add_edit_group), group)); + scroll_connection = ARDOUR_UI::instance()->SuperRapidScreenUpdate.connect + (mem_fun(*this, &Editor::update_current_screen)); } void -Editor::fake_handle_new_audio_region (AudioRegion *region) +Editor::stop_scrolling () { - Gtkmm2ext::UI::instance()->call_slot (bind (mem_fun(*this, &Editor::handle_new_audio_region), region)); -} - -void -Editor::fake_handle_audio_region_removed (AudioRegion *region) -{ - Gtkmm2ext::UI::instance()->call_slot (bind (mem_fun(*this, &Editor::handle_audio_region_removed), region)); -} - -void -Editor::fake_handle_new_duration () -{ - Gtkmm2ext::UI::instance()->call_slot (mem_fun(*this, &Editor::handle_new_duration)); -} - -void -Editor::start_scrolling () -{ - scroll_connection = ARDOUR_UI::instance()->SuperRapidScreenUpdate.connect - (mem_fun(*this, &Editor::update_current_screen)); - - slower_update_connection = ARDOUR_UI::instance()->RapidScreenUpdate.connect - (mem_fun(*this, &Editor::update_slower)); -} - -void -Editor::stop_scrolling () -{ - scroll_connection.disconnect (); - slower_update_connection.disconnect (); + scroll_connection.disconnect (); + slower_update_connection.disconnect (); } void @@ -1458,13 +1124,13 @@ Editor::map_position_change (jack_nframes_t frame) void Editor::center_screen (jack_nframes_t frame) { - float page = canvas_width * frames_per_unit; + double page = canvas_width * frames_per_unit; /* if we're off the page, then scroll. */ if (frame < leftmost_frame || frame >= leftmost_frame + page) { - center_screen_internal (frame,page); + center_screen_internal (frame, page); } } @@ -1485,18 +1151,20 @@ Editor::center_screen_internal (jack_nframes_t frame, float page) void Editor::handle_new_duration () { - reset_scrolling_region (); + ENSURE_GUI_THREAD (mem_fun (*this, &Editor::handle_new_duration)); - if (session) { - track_canvas_scroller.get_hadjustment()->set_upper (session->current_end_frame() / frames_per_unit); - track_canvas_scroller.get_hadjustment()->set_value (leftmost_frame/frames_per_unit); + jack_nframes_t new_end = session->get_maximum_extent() + (jack_nframes_t) floorf (current_page_frames() * 0.10f); + + if (new_end > last_canvas_frame) { + last_canvas_frame = new_end; + reset_scrolling_region (); } - - update_hscroller (); + + horizontal_adjustment.set_value (leftmost_frame/frames_per_unit); } void -Editor::update_title_s (string snap_name) +Editor::update_title_s (const string & snap_name) { ENSURE_GUI_THREAD(bind (mem_fun(*this, &Editor::update_title_s), snap_name)); @@ -1541,8 +1209,6 @@ Editor::connect_to_session (Session *t) first_action_message->hide(); } - flush_track_canvas(); - update_title (); session->going_away.connect (mem_fun(*this, &Editor::session_going_away)); @@ -1555,10 +1221,11 @@ Editor::connect_to_session (Session *t) session_connections.push_back (session->TransportStateChange.connect (mem_fun(*this, &Editor::map_transport_state))); session_connections.push_back (session->PositionChanged.connect (mem_fun(*this, &Editor::map_position_change))); session_connections.push_back (session->RouteAdded.connect (mem_fun(*this, &Editor::handle_new_route_p))); - session_connections.push_back (session->AudioRegionAdded.connect (mem_fun(*this, &Editor::fake_handle_new_audio_region))); - session_connections.push_back (session->AudioRegionRemoved.connect (mem_fun(*this, &Editor::fake_handle_audio_region_removed))); - session_connections.push_back (session->DurationChanged.connect (mem_fun(*this, &Editor::fake_handle_new_duration))); - session_connections.push_back (session->edit_group_added.connect (mem_fun(*this, &Editor::fake_add_edit_group))); + session_connections.push_back (session->AudioRegionAdded.connect (mem_fun(*this, &Editor::handle_new_audio_region))); + session_connections.push_back (session->AudioRegionRemoved.connect (mem_fun(*this, &Editor::handle_audio_region_removed))); + session_connections.push_back (session->DurationChanged.connect (mem_fun(*this, &Editor::handle_new_duration))); + session_connections.push_back (session->edit_group_added.connect (mem_fun(*this, &Editor::add_edit_group))); + session_connections.push_back (session->edit_group_removed.connect (mem_fun(*this, &Editor::edit_groups_changed))); session_connections.push_back (session->NamedSelectionAdded.connect (mem_fun(*this, &Editor::handle_new_named_selection))); session_connections.push_back (session->NamedSelectionRemoved.connect (mem_fun(*this, &Editor::handle_new_named_selection))); session_connections.push_back (session->DirtyChanged.connect (mem_fun(*this, &Editor::update_title))); @@ -1571,10 +1238,7 @@ Editor::connect_to_session (Session *t) session_connections.push_back (session->tempo_map().StateChanged.connect (mem_fun(*this, &Editor::tempo_map_changed))); - session->foreach_edit_group(this, &Editor::add_edit_group); - - editor_mixer_button.signal_toggled().connect (mem_fun(*this, &Editor::editor_mixer_button_toggled)); - editor_mixer_button.set_name (X_("EditorMixerButton")); + edit_groups_changed (); edit_cursor_clock.set_session (session); selection_start_clock.set_session (session); @@ -1583,6 +1247,11 @@ Editor::connect_to_session (Session *t) _playlist_selector->set_session (session); nudge_clock.set_session (session); +#ifdef FFT_ANALYSIS + if (analysis_window != 0) + analysis_window->set_session (session); +#endif + switch (session->get_edit_mode()) { case Splice: edit_mode_selector.set_active_text (edit_mode_strings[splice_index]); @@ -1625,7 +1294,7 @@ Editor::connect_to_session (Session *t) update_punch_range_view (true); session->ControlChanged.connect (mem_fun(*this, &Editor::queue_session_control_changed)); - + session->StateSaved.connect (mem_fun(*this, &Editor::session_state_saved)); refresh_location_display (); session->locations()->added.connect (mem_fun(*this, &Editor::add_new_location)); @@ -1634,26 +1303,39 @@ Editor::connect_to_session (Session *t) session->locations()->StateChanged.connect (mem_fun(*this, &Editor::refresh_location_display_s)); session->locations()->end_location()->changed.connect (mem_fun(*this, &Editor::end_location_changed)); - reset_scrolling_region (); + bool yn; + RefPtr act; + + act = ActionManager::get_action (X_("Editor"), X_("toggle-xfades-active")); + if (act) { + RefPtr tact = RefPtr::cast_dynamic(act); + /* do it twice to force the change */ + yn = session->get_crossfades_active(); + tact->set_active (!yn); + tact->set_active (yn); + } + + act = ActionManager::get_action (X_("Editor"), X_("toggle-auto-xfades")); + if (act) { + RefPtr tact = RefPtr::cast_dynamic(act); + /* do it twice to force the change */ + yn = Config->get_auto_xfade (); + tact->set_active (!yn); + tact->set_active (yn); + } + + /* xfade visibility state set from editor::set_state() */ + + update_crossfade_model (); + update_layering_model (); + + handle_new_duration (); redisplay_regions (); redisplay_named_selections (); + redisplay_snapshots (); - //route_list.freeze (); GTK2FIX - route_display_model.clear (); - session->foreach_route (this, &Editor::handle_new_route); - // route_list.select_all (); - // GTK2FIX - //route_list.sort (); - route_list_reordered (); - //route_list.thaw (); - - if (embed_audio_item) { - embed_audio_item->set_sensitive (true); - } - if (import_audio_item) { - import_audio_item->set_sensitive (true); - } + initial_route_list_display (); for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) { (static_cast(*i))->set_samples_per_unit (frames_per_unit); @@ -1666,10 +1348,8 @@ Editor::connect_to_session (Session *t) leftmost_frame = 0; - track_canvas_scroller.get_hadjustment()->set_upper (session->current_end_frame() / frames_per_unit); - track_canvas_scroller.get_hadjustment()->set_value (0); + horizontal_adjustment.set_value (0); - update_hscroller (); restore_ruler_visibility (); tempo_map_changed (Change (0)); @@ -1688,21 +1368,21 @@ Editor::connect_to_session (Session *t) TreeModel::Children rows = route_display_model->children(); TreeModel::Children::iterator i; - //route_list.freeze (); + no_route_list_redisplay = true; for (i = rows.begin(); i != rows.end(); ++i) { - TimeAxisView *tv = (*i)[route_display_columns.tv]; + TimeAxisView *tv = (*i)[route_display_columns.tv]; AudioTimeAxisView *atv; - + if ((atv = dynamic_cast(tv)) != 0) { if (atv->route().master()) { - route_list.get_selection()->unselect (i); - //(*i)->unselect (); + route_list_display.get_selection()->unselect (i); } } } - - //route_list.thaw (); + + no_route_list_redisplay = false; + redisplay_route_list (); } } @@ -1710,16 +1390,6 @@ void Editor::build_cursors () { using namespace Gdk; - - Gdk::Color fg ("#ff0000"); /* Red. */ - Gdk::Color bg ("#0000ff"); /* Blue. */ - - { - RefPtr source, mask; - source = Bitmap::create (hand_bits, hand_width, hand_height); - mask = Bitmap::create (handmask_bits, handmask_width, handmask_height); - grabber_cursor = new Gdk::Cursor (source, mask, fg, bg, hand_x_hot, hand_y_hot); - } Gdk::Color mbg ("#000000" ); /* Black */ Gdk::Color mfg ("#0000ff" ); /* Blue. */ @@ -1749,19 +1419,20 @@ Editor::build_cursors () speaker_cursor = new Gdk::Cursor (source, mask, ffg, fbg, speaker_cursor_x_hot, speaker_cursor_y_hot); } - cross_hair_cursor = new Gdk::Cursor (Gdk::CROSSHAIR); - trimmer_cursor = new Gdk::Cursor (Gdk::SB_H_DOUBLE_ARROW); - selector_cursor = new Gdk::Cursor (Gdk::XTERM); - time_fx_cursor = new Gdk::Cursor (Gdk::SIZING); - wait_cursor = new Gdk::Cursor (Gdk::WATCH); - timebar_cursor = new Gdk::Cursor(Gdk::LEFT_PTR); + grabber_cursor = new Gdk::Cursor (HAND2); + cross_hair_cursor = new Gdk::Cursor (CROSSHAIR); + trimmer_cursor = new Gdk::Cursor (SB_H_DOUBLE_ARROW); + selector_cursor = new Gdk::Cursor (XTERM); + time_fx_cursor = new Gdk::Cursor (SIZING); + wait_cursor = new Gdk::Cursor (WATCH); + timebar_cursor = new Gdk::Cursor(LEFT_PTR); } void Editor::popup_fade_context_menu (int button, int32_t time, ArdourCanvas::Item* item, ItemType item_type) { using namespace Menu_Helpers; - AudioRegionView* arv = static_cast (gtk_object_get_data (GTK_OBJECT(item), "regionview")); + AudioRegionView* arv = static_cast (item->get_data ("regionview")); if (arv == 0) { fatal << _("programming error: fade in canvas item has no regionview data pointer!") << endmsg; @@ -1872,16 +1543,18 @@ Editor::popup_track_context_menu (int button, int32_t time, ItemType item_type, if (!with_selection) { if (region_edit_menu_split_item) { if (clicked_regionview && clicked_regionview->region.covers (edit_cursor->current_frame)) { - region_edit_menu_split_item->set_sensitive (true); + ActionManager::set_sensitive (ActionManager::edit_cursor_in_region_sensitive_actions, true); } else { - region_edit_menu_split_item->set_sensitive (false); + ActionManager::set_sensitive (ActionManager::edit_cursor_in_region_sensitive_actions, false); } } if (region_edit_menu_split_multichannel_item) { if (clicked_regionview && clicked_regionview->region.n_channels() > 1) { - region_edit_menu_split_multichannel_item->set_sensitive (true); + // GTK2FIX find the action, change its sensitivity + // region_edit_menu_split_multichannel_item->set_sensitive (true); } else { - region_edit_menu_split_multichannel_item->set_sensitive (false); + // GTK2FIX see above + // region_edit_menu_split_multichannel_item->set_sensitive (false); } } } @@ -2020,6 +1693,46 @@ Editor::build_track_crossfade_context_menu (jack_nframes_t frame) return &track_crossfade_context_menu; } +#ifdef FFT_ANALYSIS +void +Editor::analyze_region_selection() +{ + if (analysis_window == 0) { + analysis_window = new AnalysisWindow(); + + if (session != 0) + analysis_window->set_session(session); + + analysis_window->show_all(); + } + + analysis_window->set_regionmode(); + analysis_window->analyze(); + + analysis_window->present(); +} + +void +Editor::analyze_range_selection() +{ + if (analysis_window == 0) { + analysis_window = new AnalysisWindow(); + + if (session != 0) + analysis_window->set_session(session); + + analysis_window->show_all(); + } + + analysis_window->set_rangemode(); + analysis_window->analyze(); + + analysis_window->present(); +} +#endif /* FFT_ANALYSIS */ + + + Menu* Editor::build_track_selection_context_menu (jack_nframes_t ignored) { @@ -2121,6 +1834,11 @@ Editor::add_region_context_items (StreamView* sv, Region* region, Menu_Helpers:: items.push_back (MenuElem (_("Audition"), mem_fun(*this, &Editor::audition_selected_region))); items.push_back (MenuElem (_("Export"), mem_fun(*this, &Editor::export_region))); items.push_back (MenuElem (_("Bounce"), mem_fun(*this, &Editor::bounce_region_selection))); + +#ifdef FFT_ANALYSIS + items.push_back (MenuElem (_("Analyze region"), mem_fun(*this, &Editor::analyze_region_selection))); +#endif + items.push_back (SeparatorElem()); /* XXX hopefully this nonsense will go away with SigC++ 2.X, where the compiler @@ -2160,6 +1878,13 @@ Editor::add_region_context_items (StreamView* sv, Region* region, Menu_Helpers:: items.push_back (MenuElem (_("Reverse"), mem_fun(*this, &Editor::reverse_region))); items.push_back (SeparatorElem()); + + /* range related stuff */ + + items.push_back (MenuElem (_("Add Range Markers"), mem_fun (*this, &Editor::add_location_from_audio_region))); + items.push_back (MenuElem (_("Set Range"), mem_fun (*this, &Editor::set_selection_from_audio_region))); + items.push_back (SeparatorElem()); + /* Nudge region */ Menu *nudge_menu = manage (new Menu()); @@ -2227,20 +1952,30 @@ Editor::add_selection_context_items (Menu_Helpers::MenuList& edit_items) items.push_back (MenuElem (_("Play range"), mem_fun(*this, &Editor::play_selection))); items.push_back (MenuElem (_("Loop range"), mem_fun(*this, &Editor::set_route_loop_selection))); + +#ifdef FFT_ANALYSIS items.push_back (SeparatorElem()); - items.push_back (MenuElem (_("Create chunk from range"), mem_fun(*this, &Editor::name_selection))); + items.push_back (MenuElem (_("Analyze range"), mem_fun(*this, &Editor::analyze_range_selection))); +#endif + items.push_back (SeparatorElem()); - items.push_back (MenuElem (_("Create Region"), mem_fun(*this, &Editor::new_region_from_selection))); - items.push_back (MenuElem (_("Separate Region"), mem_fun(*this, &Editor::separate_region_from_selection))); - items.push_back (MenuElem (_("Crop Region to range"), mem_fun(*this, &Editor::crop_region_to_selection))); - items.push_back (MenuElem (_("Bounce range"), mem_fun(*this, &Editor::bounce_range_selection))); + items.push_back (MenuElem (_("Separate range to track"), mem_fun(*this, &Editor::separate_region_from_selection))); + items.push_back (MenuElem (_("Separate range to region list"), mem_fun(*this, &Editor::new_region_from_selection))); + items.push_back (SeparatorElem()); - items.push_back (MenuElem (_("Duplicate"), bind (mem_fun(*this, &Editor::duplicate_dialog), false))); + items.push_back (MenuElem (_("Select all in range"), mem_fun(*this, &Editor::select_all_selectables_using_time_selection))); items.push_back (SeparatorElem()); - items.push_back (MenuElem (_("Export"), mem_fun(*this, &Editor::export_selection))); + items.push_back (MenuElem (_("Set range to loop range"), mem_fun(*this, &Editor::set_selection_from_loop))); + items.push_back (MenuElem (_("Set range to punch range"), mem_fun(*this, &Editor::set_selection_from_punch))); items.push_back (SeparatorElem()); - items.push_back (MenuElem (_("Fill range w/Region"), mem_fun(*this, &Editor::region_fill_selection))); - + items.push_back (MenuElem (_("Crop region to range"), mem_fun(*this, &Editor::crop_region_to_selection))); + items.push_back (MenuElem (_("Fill range with region"), mem_fun(*this, &Editor::region_fill_selection))); + items.push_back (MenuElem (_("Duplicate range"), bind (mem_fun(*this, &Editor::duplicate_dialog), false))); + items.push_back (MenuElem (_("Create chunk from range"), mem_fun(*this, &Editor::name_selection))); + items.push_back (SeparatorElem()); + items.push_back (MenuElem (_("Bounce range"), mem_fun(*this, &Editor::bounce_range_selection))); + items.push_back (MenuElem (_("Export range"), mem_fun(*this, &Editor::export_selection))); + edit_items.push_back (MenuElem (_("Range"), *selection_menu)); edit_items.push_back (SeparatorElem()); } @@ -2270,13 +2005,19 @@ Editor::add_dstream_context_items (Menu_Helpers::MenuList& edit_items) MenuList& select_items = select_menu->items(); select_menu->set_name ("ArdourContextMenu"); - select_items.push_back (MenuElem (_("Select All in track"), bind (mem_fun(*this, &Editor::select_all_in_track), false))); - select_items.push_back (MenuElem (_("Select All"), bind (mem_fun(*this, &Editor::select_all), false))); - select_items.push_back (MenuElem (_("Invert in track"), mem_fun(*this, &Editor::invert_selection_in_track))); - select_items.push_back (MenuElem (_("Invert"), mem_fun(*this, &Editor::invert_selection))); + select_items.push_back (MenuElem (_("Select All in track"), bind (mem_fun(*this, &Editor::select_all_in_track), Selection::Set))); + select_items.push_back (MenuElem (_("Select All"), bind (mem_fun(*this, &Editor::select_all), Selection::Set))); + select_items.push_back (MenuElem (_("Invert selection in track"), mem_fun(*this, &Editor::invert_selection_in_track))); + select_items.push_back (MenuElem (_("Invert selection"), mem_fun(*this, &Editor::invert_selection))); + select_items.push_back (SeparatorElem()); + select_items.push_back (MenuElem (_("Set range to loop range"), mem_fun(*this, &Editor::set_selection_from_loop))); + select_items.push_back (MenuElem (_("Set range to punch range"), mem_fun(*this, &Editor::set_selection_from_punch))); select_items.push_back (SeparatorElem()); - select_items.push_back (MenuElem (_("Select loop range"), mem_fun(*this, &Editor::set_selection_from_loop))); - select_items.push_back (MenuElem (_("Select punch range"), mem_fun(*this, &Editor::set_selection_from_punch))); + select_items.push_back (MenuElem (_("Select all after edit cursor"), bind (mem_fun(*this, &Editor::select_all_selectables_using_cursor), edit_cursor, true))); + select_items.push_back (MenuElem (_("Select all before edit cursor"), bind (mem_fun(*this, &Editor::select_all_selectables_using_cursor), edit_cursor, false))); + select_items.push_back (MenuElem (_("Select all after playhead"), bind (mem_fun(*this, &Editor::select_all_selectables_using_cursor), playhead_cursor, true))); + select_items.push_back (MenuElem (_("Select all before playhead"), bind (mem_fun(*this, &Editor::select_all_selectables_using_cursor), playhead_cursor, false))); + select_items.push_back (MenuElem (_("Select all between cursors"), bind (mem_fun(*this, &Editor::select_all_selectables_between_cursors), playhead_cursor, edit_cursor))); select_items.push_back (SeparatorElem()); edit_items.push_back (MenuElem (_("Select"), *select_menu)); @@ -2301,23 +2042,13 @@ Editor::add_dstream_context_items (Menu_Helpers::MenuList& edit_items) cutnpaste_items.push_back (MenuElem (_("Insert chunk"), bind (mem_fun(*this, &Editor::paste_named_selection), 1.0f))); - cutnpaste_items.push_back (SeparatorElem()); - - cutnpaste_items.push_back (MenuElem (_("New Region from range"), mem_fun(*this, &Editor::new_region_from_selection))); - cutnpaste_items.push_back (MenuElem (_("Separate Range"), mem_fun(*this, &Editor::separate_region_from_selection))); - edit_items.push_back (MenuElem (_("Edit"), *cutnpaste_menu)); /* Adding new material */ - Menu *import_menu = manage (new Menu()); - MenuList& import_items = import_menu->items(); - import_menu->set_name ("ArdourContextMenu"); - - import_items.push_back (MenuElem (_("Insert Region"), bind (mem_fun(*this, &Editor::insert_region_list_selection), 1.0f))); - import_items.push_back (MenuElem (_("Insert external sndfile"), bind (mem_fun(*this, &Editor::insert_sndfile), false))); - - edit_items.push_back (MenuElem (_("Import"), *import_menu)); + edit_items.push_back (SeparatorElem()); + edit_items.push_back (MenuElem (_("Insert Selected Region"), bind (mem_fun(*this, &Editor::insert_region_list_selection), 1.0f))); + edit_items.push_back (MenuElem (_("Insert Existing Audio"), bind (mem_fun(*this, &Editor::add_external_audio_action), ImportToTrack))); /* Nudge track */ @@ -2355,14 +2086,15 @@ Editor::add_bus_context_items (Menu_Helpers::MenuList& edit_items) MenuList& select_items = select_menu->items(); select_menu->set_name ("ArdourContextMenu"); - select_items.push_back (MenuElem (_("Select All in track"), bind (mem_fun(*this, &Editor::select_all_in_track), false))); - select_items.push_back (MenuElem (_("Select All"), bind (mem_fun(*this, &Editor::select_all), false))); - select_items.push_back (MenuElem (_("Invert in track"), mem_fun(*this, &Editor::invert_selection_in_track))); - select_items.push_back (MenuElem (_("Invert"), mem_fun(*this, &Editor::invert_selection))); - select_items.push_back (SeparatorElem()); - select_items.push_back (MenuElem (_("Select loop range"), mem_fun(*this, &Editor::set_selection_from_loop))); - select_items.push_back (MenuElem (_("Select punch range"), mem_fun(*this, &Editor::set_selection_from_punch))); + select_items.push_back (MenuElem (_("Select All in track"), bind (mem_fun(*this, &Editor::select_all_in_track), Selection::Set))); + select_items.push_back (MenuElem (_("Select All"), bind (mem_fun(*this, &Editor::select_all), Selection::Set))); + select_items.push_back (MenuElem (_("Invert selection in track"), mem_fun(*this, &Editor::invert_selection_in_track))); + select_items.push_back (MenuElem (_("Invert selection"), mem_fun(*this, &Editor::invert_selection))); select_items.push_back (SeparatorElem()); + select_items.push_back (MenuElem (_("Select all after edit cursor"), bind (mem_fun(*this, &Editor::select_all_selectables_using_cursor), edit_cursor, true))); + select_items.push_back (MenuElem (_("Select all before edit cursor"), bind (mem_fun(*this, &Editor::select_all_selectables_using_cursor), edit_cursor, false))); + select_items.push_back (MenuElem (_("Select all after playhead"), bind (mem_fun(*this, &Editor::select_all_selectables_using_cursor), playhead_cursor, true))); + select_items.push_back (MenuElem (_("Select all before playhead"), bind (mem_fun(*this, &Editor::select_all_selectables_using_cursor), playhead_cursor, false))); edit_items.push_back (MenuElem (_("Select"), *select_menu)); @@ -2423,54 +2155,19 @@ Editor::set_snap_mode (SnapMode mode) instant_save (); } -void -Editor::add_location_from_selection () -{ - if (selection->time.empty()) { - return; - } - - if (session == 0 || clicked_trackview == 0) { - return; - } - - jack_nframes_t start = selection->time[clicked_selection].start; - jack_nframes_t end = selection->time[clicked_selection].end; - - Location *location = new Location (start, end, "selection"); - - session->begin_reversible_command (_("add marker")); - session->add_undo (session->locations()->get_memento()); - session->locations()->add (location, true); - session->add_redo_no_execute (session->locations()->get_memento()); - session->commit_reversible_command (); -} - -void -Editor::add_location_from_playhead_cursor () -{ - jack_nframes_t where = session->audible_frame(); - - Location *location = new Location (where, where, "mark", Location::IsMark); - session->begin_reversible_command (_("add marker")); - session->add_undo (session->locations()->get_memento()); - session->locations()->add (location, true); - session->add_redo_no_execute (session->locations()->get_memento()); - session->commit_reversible_command (); -} - - int Editor::set_state (const XMLNode& node) { const XMLProperty* prop; XMLNode* geometry; - int x, y, width, height, xoff, yoff; + int x, y, xoff, yoff; + Gdk::Geometry g; + if ((geometry = find_named_node (node, "geometry")) == 0) { - width = default_width; - height = default_height; + g.base_width = default_width; + g.base_height = default_height; x = 1; y = 1; xoff = 0; @@ -2478,24 +2175,24 @@ Editor::set_state (const XMLNode& node) } else { - width = atoi(geometry->property("x_size")->value()); - height = atoi(geometry->property("y_size")->value()); + g.base_width = atoi(geometry->property("x_size")->value()); + g.base_height = atoi(geometry->property("y_size")->value()); x = atoi(geometry->property("x_pos")->value()); y = atoi(geometry->property("y_pos")->value()); xoff = atoi(geometry->property("x_off")->value()); yoff = atoi(geometry->property("y_off")->value()); } - set_default_size(width, height); - // GTK2FIX - // set_position(x, y-yoff); + set_geometry_hints (vpacker, g, Gdk::HINT_BASE_SIZE); + set_default_size (g.base_width, g.base_height); + move (x, y); if ((prop = node.property ("zoom-focus"))) { set_zoom_focus ((ZoomFocus) atoi (prop->value())); } if ((prop = node.property ("zoom"))) { - set_frames_per_unit (atof (prop->value())); + set_frames_per_unit (PBD::atof (prop->value())); } if ((prop = node.property ("snap-to"))) { @@ -2506,52 +2203,86 @@ Editor::set_state (const XMLNode& node) set_snap_mode ((SnapMode) atoi (prop->value())); } + if ((prop = node.property ("mouse-mode"))) { + MouseMode m = str2mousemode(prop->value()); + mouse_mode = MouseMode ((int) m + 1); /* lie, force mode switch */ + set_mouse_mode (m, true); + } else { + mouse_mode = MouseGain; /* lie, to force the mode switch */ + set_mouse_mode (MouseObject, true); + } + if ((prop = node.property ("show-waveforms"))) { bool yn = (prop->value() == "yes"); _show_waveforms = !yn; - set_show_waveforms (yn); + RefPtr act = ActionManager::get_action (X_("Editor"), X_("ToggleWaveformVisibility")); + if (act) { + RefPtr tact = RefPtr::cast_dynamic(act); + /* do it twice to force the change */ + tact->set_active (!yn); + tact->set_active (yn); + } } if ((prop = node.property ("show-waveforms-recording"))) { bool yn = (prop->value() == "yes"); _show_waveforms_recording = !yn; - set_show_waveforms_recording (yn); + RefPtr act = ActionManager::get_action (X_("Editor"), X_("ToggleWaveformsWhileRecording")); + if (act) { + RefPtr tact = RefPtr::cast_dynamic(act); + /* do it twice to force the change */ + tact->set_active (!yn); + tact->set_active (yn); + } } if ((prop = node.property ("show-measures"))) { bool yn = (prop->value() == "yes"); _show_measures = !yn; - set_show_measures (yn); + RefPtr act = ActionManager::get_action (X_("Editor"), X_("ToggleMeasureVisibility")); + if (act) { + RefPtr tact = RefPtr::cast_dynamic(act); + /* do it twice to force the change */ + tact->set_active (!yn); + tact->set_active (yn); + } } if ((prop = node.property ("follow-playhead"))) { bool yn = (prop->value() == "yes"); - _follow_playhead = !yn; - set_follow_playhead (yn); + RefPtr act = ActionManager::get_action (X_("Editor"), X_("toggle-follow-playhead")); + if (act) { + RefPtr tact = RefPtr::cast_dynamic(act); + /* do it twice to force the change */ + tact->set_active (!yn); + tact->set_active (yn); + } } - if ((prop = node.property ("xfades-visible"))) { - bool yn = (prop->value() == "yes"); - _xfade_visibility = !yn; - set_xfade_visibility (yn); - } if ((prop = node.property ("region-list-sort-type"))) { - region_list_sort_type = (Editing::RegionListSortType) -1; /* force change */ + region_list_sort_type = (Editing::RegionListSortType) -1; // force change reset_region_list_sort_type(str2regionlistsorttype(prop->value())); } - if ((prop = node.property ("mouse-mode"))) { - MouseMode m = str2mousemode(prop->value()); - mouse_mode = MouseMode ((int) m + 1); /* lie, force mode switch */ - set_mouse_mode (m, true); - } else { - mouse_mode = MouseGain; /* lie, to force the mode switch */ - set_mouse_mode (MouseObject, true); + if ((prop = node.property ("xfades-visible"))) { + bool yn = (prop->value() == "yes"); + _xfade_visibility = !yn; + // set_xfade_visibility (yn); } - if ((prop = node.property ("editor-mixer-button"))) { - editor_mixer_button.set_active(prop->value() == "yes"); + if ((prop = node.property ("show-editor-mixer"))) { + + Glib::RefPtr act = ActionManager::get_action (X_("Editor"), X_("show-editor-mixer")); + if (act) { + Glib::RefPtr tact = Glib::RefPtr::cast_dynamic(act); + bool yn = (prop->value() == X_("yes")); + + /* do it twice to force the change */ + + tact->set_active (!yn); + tact->set_active (yn); + } } return 0; @@ -2585,14 +2316,8 @@ Editor::get_state () geometry->add_property("x_off", string(buf)); snprintf(buf, sizeof(buf), "%d", yoff); geometry->add_property("y_off", string(buf)); - snprintf(buf,sizeof(buf), "%d",gtk_paned_get_position (static_cast(&canvas_region_list_pane)->gobj())); - geometry->add_property("canvas_region_list_pane_pos", string(buf)); - snprintf(buf,sizeof(buf), "%d", gtk_paned_get_position (static_cast(&track_list_canvas_pane)->gobj())); - geometry->add_property("track_list_canvas_pane_pos", string(buf)); - snprintf(buf,sizeof(buf), "%d", gtk_paned_get_position (static_cast(®ion_selection_vpane)->gobj())); - geometry->add_property("region_selection_pane_pos", string(buf)); - snprintf(buf,sizeof(buf), "%d", gtk_paned_get_position (static_cast(&route_group_vpane)->gobj())); - geometry->add_property("route_group_pane_pos", string(buf)); + snprintf(buf,sizeof(buf), "%d",gtk_paned_get_position (static_cast(&edit_pane)->gobj())); + geometry->add_property("edit_pane_pos", string(buf)); node->add_child_nocopy (*geometry); } @@ -2613,8 +2338,13 @@ Editor::get_state () node->add_property ("xfades-visible", _xfade_visibility ? "yes" : "no"); node->add_property ("region-list-sort-type", enum2str(region_list_sort_type)); node->add_property ("mouse-mode", enum2str(mouse_mode)); - node->add_property ("editor-mixer-button", editor_mixer_button.get_active() ? "yes" : "no"); + Glib::RefPtr act = ActionManager::get_action (X_("Editor"), X_("show-editor-mixer")); + if (act) { + Glib::RefPtr tact = Glib::RefPtr::cast_dynamic(act); + node->add_property (X_("show-editor-mixer"), tact->get_active() ? "yes" : "no"); + } + return *node; } @@ -2880,10 +2610,14 @@ Editor::setup_toolbar () mouse_mode_tearoff = manage (new TearOff (mouse_mode_button_table)); mouse_mode_tearoff->set_name ("MouseModeBase"); - mouse_mode_tearoff->Detach.connect (bind (mem_fun(*this, &Editor::detach_tearoff), static_cast(&toolbar_hbox), - mouse_mode_tearoff->tearoff_window())); - mouse_mode_tearoff->Attach.connect (bind (mem_fun(*this, &Editor::reattach_tearoff), static_cast (&toolbar_hbox), - mouse_mode_tearoff->tearoff_window(), 1)); + mouse_mode_tearoff->Detach.connect (bind (mem_fun(*this, &Editor::detach_tearoff), static_cast(&toolbar_hbox), + &mouse_mode_tearoff->tearoff_window())); + mouse_mode_tearoff->Attach.connect (bind (mem_fun(*this, &Editor::reattach_tearoff), static_cast (&toolbar_hbox), + &mouse_mode_tearoff->tearoff_window(), 1)); + mouse_mode_tearoff->Hidden.connect (bind (mem_fun(*this, &Editor::detach_tearoff), static_cast(&toolbar_hbox), + &mouse_mode_tearoff->tearoff_window())); + mouse_mode_tearoff->Visible.connect (bind (mem_fun(*this, &Editor::reattach_tearoff), static_cast (&toolbar_hbox), + &mouse_mode_tearoff->tearoff_window(), 1)); mouse_move_button.set_name ("MouseModeButton"); mouse_select_button.set_name ("MouseModeButton"); @@ -2899,12 +2633,12 @@ Editor::setup_toolbar () ARDOUR_UI::instance()->tooltips().set_tip (mouse_timefx_button, _("stretch/shrink regions")); ARDOUR_UI::instance()->tooltips().set_tip (mouse_audition_button, _("listen to specific regions")); - mouse_move_button.unset_flags (Gtk::CAN_FOCUS); - mouse_select_button.unset_flags (Gtk::CAN_FOCUS); - mouse_gain_button.unset_flags (Gtk::CAN_FOCUS); - mouse_zoom_button.unset_flags (Gtk::CAN_FOCUS); - mouse_timefx_button.unset_flags (Gtk::CAN_FOCUS); - mouse_audition_button.unset_flags (Gtk::CAN_FOCUS); + mouse_move_button.unset_flags (CAN_FOCUS); + mouse_select_button.unset_flags (CAN_FOCUS); + mouse_gain_button.unset_flags (CAN_FOCUS); + mouse_zoom_button.unset_flags (CAN_FOCUS); + mouse_timefx_button.unset_flags (CAN_FOCUS); + mouse_audition_button.unset_flags (CAN_FOCUS); mouse_select_button.signal_toggled().connect (bind (mem_fun(*this, &Editor::mouse_mode_toggled), Editing::MouseRange)); mouse_select_button.signal_button_release_event().connect (mem_fun(*this, &Editor::mouse_select_button_release)); @@ -2938,7 +2672,8 @@ Editor::setup_toolbar () /* XXX another disgusting hack because of the way combo boxes size themselves */ - Gtkmm2ext::set_size_request_to_display_given_text (edit_mode_selector, "EdgtMode", 2, 10); + const guint32 FUDGE = 20; // Combo's are stupid - they steal space from the entry for the button + Gtkmm2ext::set_size_request_to_display_given_text (edit_mode_selector, "EdgtMode", 2+FUDGE, 10); set_popdown_strings (edit_mode_selector, internationalize (edit_mode_strings)); edit_mode_box.pack_start (edit_mode_label, false, false); edit_mode_box.pack_start (edit_mode_selector, false, false); @@ -2956,8 +2691,7 @@ Editor::setup_toolbar () /* XXX another disgusting hack because of the way combo boxes size themselves */ - const guint32 FUDGE = 10; // Combo's are stupid - they steal space from the entry for the button - Gtkmm2ext::set_size_request_to_display_given_text (snap_type_selector, "Region bounds", 2+FUDGE, 10); + Gtkmm2ext::set_size_request_to_display_given_text (snap_type_selector, "SMPTE Seconds", 2+FUDGE, 10); set_popdown_strings (snap_type_selector, internationalize (snap_type_strings)); snap_type_box.pack_start (snap_type_label, false, false); @@ -2974,7 +2708,7 @@ Editor::setup_toolbar () snap_mode_box.set_spacing (3); snap_mode_box.set_border_width (3); - Gtkmm2ext::set_size_request_to_display_given_text (snap_mode_selector, "SngpMode", 2, 10); + Gtkmm2ext::set_size_request_to_display_given_text (snap_mode_selector, "SngpMode", 2+FUDGE, 10); set_popdown_strings (snap_mode_selector, internationalize (snap_mode_strings)); snap_mode_box.pack_start (snap_mode_label, false, false); @@ -2993,7 +2727,7 @@ Editor::setup_toolbar () /* XXX another disgusting hack because of the way combo boxes size themselves */ - Gtkmm2ext::set_size_request_to_display_given_text (zoom_focus_selector, "Edgt Cursor", 2, 10); + Gtkmm2ext::set_size_request_to_display_given_text (zoom_focus_selector, "Edgt Cursor", 2+FUDGE, 10); set_popdown_strings (zoom_focus_selector, internationalize (zoom_focus_strings)); zoom_focus_box.pack_start (zoom_focus_label, false, false); @@ -3010,32 +2744,38 @@ Editor::setup_toolbar () selection_start_clock_label.set_text (_("Start:")); selection_end_clock_label.set_text (_("End:")); - edit_cursor_clock_label.set_text (_("Edit:")); + edit_cursor_clock_label.set_text (_("Edit")); - toolbar_selection_clock_table.set_border_width (5); - toolbar_selection_clock_table.set_col_spacings (2); - toolbar_selection_clock_table.set_homogeneous (false); + /* the zoom in/out buttons are generally taller than the clocks, so + put all the toolbar clocks into a size group with one of the + buttons to make them all equal height. -// toolbar_selection_clock_table.attach (selection_start_clock_label, 0, 1, 0, 1, 0, 0, 0, 0); -// toolbar_selection_clock_table.attach (selection_end_clock_label, 1, 2, 0, 1, 0, 0, 0, 0); - toolbar_selection_clock_table.attach (edit_cursor_clock_label, 2, 3, 0, 1, FILL, FILL, 0, 0); + this also applies to the various toolbar combos + */ -// toolbar_selection_clock_table.attach (selection_start_clock, 0, 1, 1, 2, 0, 0); -// toolbar_selection_clock_table.attach (selection_end_clock, 1, 2, 1, 2, 0, 0); - toolbar_selection_clock_table.attach (edit_cursor_clock, 2, 3, 1, 2, FILL, FILL); + RefPtr toolbar_clock_size_group = SizeGroup::create (SIZE_GROUP_VERTICAL); + toolbar_clock_size_group->add_widget (zoom_out_button); + toolbar_clock_size_group->add_widget (edit_cursor_clock); + toolbar_clock_size_group->add_widget (zoom_range_clock); + toolbar_clock_size_group->add_widget (nudge_clock); + toolbar_clock_size_group->add_widget (edit_mode_selector); + toolbar_clock_size_group->add_widget (snap_type_selector); + toolbar_clock_size_group->add_widget (snap_mode_selector); + toolbar_clock_size_group->add_widget (zoom_focus_selector); + HBox* edit_clock_hbox = manage (new HBox()); + VBox* edit_clock_vbox = manage (new VBox()); -// toolbar_clock_vbox.set_spacing (2); -// toolbar_clock_vbox.set_border_width (10); - /* the editor/mixer button will be enabled at session connect */ + edit_clock_hbox->pack_start (edit_cursor_clock, false, false); - editor_mixer_button.set_active(false); - editor_mixer_button.set_sensitive(false); + edit_clock_vbox->set_spacing (3); + edit_clock_vbox->set_border_width (3); + edit_clock_vbox->pack_start (edit_cursor_clock_label, false, false); + edit_clock_vbox->pack_start (*edit_clock_hbox, false, false); HBox* hbox = new HBox; - hbox->pack_start (editor_mixer_button, false, false); - hbox->pack_start (toolbar_selection_clock_table, false, false); + hbox->pack_start (*edit_clock_vbox, false, false); hbox->pack_start (zoom_indicator_vbox, false, false); hbox->pack_start (zoom_focus_box, false, false); hbox->pack_start (snap_type_box, false, false); @@ -3068,11 +2808,14 @@ Editor::setup_toolbar () tools_tearoff = new TearOff (*hbox); tools_tearoff->set_name ("MouseModeBase"); - tools_tearoff->Detach.connect (bind (mem_fun(*this, &Editor::detach_tearoff), static_cast(&toolbar_hbox), - tools_tearoff->tearoff_window())); - tools_tearoff->Attach.connect (bind (mem_fun(*this, &Editor::reattach_tearoff), static_cast (&toolbar_hbox), - tools_tearoff->tearoff_window(), 0)); - + tools_tearoff->Detach.connect (bind (mem_fun(*this, &Editor::detach_tearoff), static_cast(&toolbar_hbox), + &tools_tearoff->tearoff_window())); + tools_tearoff->Attach.connect (bind (mem_fun(*this, &Editor::reattach_tearoff), static_cast (&toolbar_hbox), + &tools_tearoff->tearoff_window(), 0)); + tools_tearoff->Hidden.connect (bind (mem_fun(*this, &Editor::detach_tearoff), static_cast(&toolbar_hbox), + &tools_tearoff->tearoff_window())); + tools_tearoff->Visible.connect (bind (mem_fun(*this, &Editor::reattach_tearoff), static_cast (&toolbar_hbox), + &tools_tearoff->tearoff_window(), 0)); toolbar_hbox.set_spacing (8); toolbar_hbox.set_border_width (2); @@ -3083,232 +2826,86 @@ Editor::setup_toolbar () toolbar_base.set_name ("ToolBarBase"); toolbar_base.add (toolbar_hbox); - toolbar_frame.set_shadow_type (Gtk::SHADOW_OUT); + toolbar_frame.set_shadow_type (SHADOW_OUT); toolbar_frame.set_name ("BaseFrame"); toolbar_frame.add (toolbar_base); } -gint -Editor::_autoscroll_canvas (void *arg) -{ - return ((Editor *) arg)->autoscroll_canvas (); -} - -gint -Editor::autoscroll_canvas () -{ - jack_nframes_t new_frame; - bool keep_calling = true; - - if (autoscroll_direction < 0) { - if (leftmost_frame < autoscroll_distance) { - new_frame = 0; - } else { - new_frame = leftmost_frame - autoscroll_distance; - } - } else { - if (leftmost_frame > max_frames - autoscroll_distance) { - new_frame = max_frames; - } else { - new_frame = leftmost_frame + autoscroll_distance; - } - } - - if (new_frame != leftmost_frame) { - reposition_x_origin (new_frame); - } - - if (new_frame == 0 || new_frame == max_frames) { - /* we are done */ - return FALSE; - } - - autoscroll_cnt++; - - if (autoscroll_cnt == 1) { - - /* connect the timeout so that we get called repeatedly */ - - autoscroll_timeout_tag = gtk_timeout_add (100, _autoscroll_canvas, this); - keep_calling = false; - - } else if (autoscroll_cnt > 10 && autoscroll_cnt < 20) { - - /* after about a while, speed up a bit by changing the timeout interval */ - - autoscroll_timeout_tag = gtk_timeout_add (50, _autoscroll_canvas, this); - keep_calling = false; - - } else if (autoscroll_cnt >= 20 && autoscroll_cnt < 30) { - - /* after about another while, speed up some more */ - - autoscroll_timeout_tag = gtk_timeout_add (25, _autoscroll_canvas, this); - keep_calling = false; - - } else if (autoscroll_cnt >= 30) { - - /* we've been scrolling for a while ... crank it up */ - - autoscroll_distance = 10 * (jack_nframes_t) floor (canvas_width * frames_per_unit); - } - - return keep_calling; -} - -void -Editor::start_canvas_autoscroll (int dir) -{ - if (!session) { - return; - } - - stop_canvas_autoscroll (); - - autoscroll_direction = dir; - autoscroll_distance = (jack_nframes_t) floor ((canvas_width * frames_per_unit)/10.0); - autoscroll_cnt = 0; - - /* do it right now, which will start the repeated callbacks */ - - autoscroll_canvas (); -} - -void -Editor::stop_canvas_autoscroll () -{ - if (autoscroll_timeout_tag >= 0) { - gtk_timeout_remove (autoscroll_timeout_tag); - autoscroll_timeout_tag = -1; - } -} - int -Editor::convert_drop_to_paths (vector& paths, - GdkDragContext *context, +Editor::convert_drop_to_paths (vector& paths, + const RefPtr& context, gint x, gint y, - GtkSelectionData *data, + const SelectionData& data, guint info, guint time) { - string spath; - char *path; - int state; - gchar *tname = gdk_atom_name (data->type); - - if (session == 0 || strcmp (tname, "text/plain") != 0) { + if (session == 0) { return -1; } - /* Parse the "uri-list" format that Nautilus provides, - where each pathname is delimited by \r\n - */ + vector uris = data.get_uris(); - path = (char *) data->data; - state = 0; + if (uris.empty()) { + + /* This is seriously fucked up. Nautilus doesn't say that its URI lists + are actually URI lists. So do it by hand. + */ - for (int n = 0; n < data->length; ++n) { + if (data.get_target() != "text/plain") { + return -1; + } + + /* Parse the "uri-list" format that Nautilus provides, + where each pathname is delimited by \r\n + */ + + const char* p = data.get_text().c_str(); + const char* q; - switch (state) { - case 0: - if (path[n] == '\r') { - state = 1; - } else { - spath += path[n]; - } - break; - case 1: - if (path[n] == '\n') { - paths.push_back (spath); - spath = ""; - state = 0; - } else { - warning << _("incorrectly formatted URI list, ignored") - << endmsg; - return -1; + while (p) + { + if (*p != '#') + { + while (g_ascii_isspace (*p)) + p++; + + q = p; + while (*q && (*q != '\n') && (*q != '\r')) + q++; + + if (q > p) + { + q--; + while (q > p && g_ascii_isspace (*q)) + q--; + + if (q > p) + { + uris.push_back (ustring (p, q - p + 1)); + } + } } - break; + p = strchr (p, '\n'); + if (p) + p++; } - } - - /* nautilus and presumably some other file managers prefix even text/plain with file:// */ - - for (vector::iterator p = paths.begin(); p != paths.end(); ++p) { - - // cerr << "dropped text was " << *p << endl; - - url_decode (*p); - - // cerr << "decoded was " << *p << endl; - if ((*p).substr (0,7) == "file://") { - (*p) = (*p).substr (7); + if (uris.empty()) { + return -1; } } - return 0; -} - -void -Editor::track_canvas_drag_data_received (GdkDragContext *context, - gint x, - gint y, - GtkSelectionData *data, - guint info, - guint time) -{ - TimeAxisView* tvp; - AudioTimeAxisView* tv; - double cy; - vector paths; - string spath; - GdkEvent ev; - jack_nframes_t frame; - - if (convert_drop_to_paths (paths, context, x, y, data, info, time)) { - goto out; - } - - /* D-n-D coordinates are window-relative, so convert to "world" coordinates - */ - - double wx; - double wy; - - track_canvas.c2w( x, y, wx, wy); - - ev.type = GDK_BUTTON_RELEASE; - ev.button.x = wx; - ev.button.y = wy; - - frame = event_frame (&ev, 0, &cy); - - snap_to (frame); - - if ((tvp = trackview_by_y_position (cy)) == 0) { - - /* drop onto canvas background: create a new track */ - - insert_paths_as_new_tracks (paths, false); - - - } else if ((tv = dynamic_cast(tvp)) != 0) { - - /* check that its an audio track, not a bus */ - - if (tv->get_diskstream()) { - - for (vector::iterator p = paths.begin(); p != paths.end(); ++p) { - insert_sndfile_into (*p, true, tv, frame); - } + for (vector::iterator i = uris.begin(); i != uris.end(); ++i) { + if ((*i).substr (0,7) == "file://") { + string p = *i; + PBD::url_decode (p); + paths.push_back (p.substr (7)); } - } - out: - gtk_drag_finish (context, TRUE, FALSE, time); + return 0; } void @@ -3363,7 +2960,7 @@ Editor::restore_state (State *state) *selection = *state->selection; time_selection_changed (); - region_selection_changed (); + region_selection_changed (); /* XXX other selection change handlers? */ } @@ -3386,178 +2983,344 @@ Editor::commit_reversible_command () } } -void -Editor::flush_track_canvas () +bool +Editor::set_selected_track_from_click (bool press, Selection::Operation op, bool with_undo, bool no_remove) { - /* I don't think this is necessary, and only causes more problems. - I'm commenting it out - and if the imageframe folks don't have any issues, we can take - out this method entirely - */ - - //gnome_canvas_update_now (GNOME_CANVAS(track_canvas)); - //gtk_main_iteration (); -} + bool commit = false; -void -Editor::set_selected_track_from_click (bool add, bool with_undo, bool no_remove) -{ if (!clicked_trackview) { - return; - } - - if (with_undo) { - begin_reversible_command (_("set selected trackview")); + return false; } - if (add) { - + switch (op) { + case Selection::Toggle: if (selection->selected (clicked_trackview)) { if (!no_remove) { selection->remove (clicked_trackview); + commit = true; } } else { selection->add (clicked_trackview); + commit = false; } - - } else { + break; + case Selection::Set: if (selection->selected (clicked_trackview) && selection->tracks.size() == 1) { /* no commit necessary */ - return; } selection->set (clicked_trackview); + break; + + case Selection::Extend: + /* not defined yet */ + break; } - - if (with_undo) { - commit_reversible_command (); - } + + return commit; } -void -Editor::set_selected_control_point_from_click (bool add, bool with_undo, bool no_remove) +bool +Editor::set_selected_control_point_from_click (bool press, Selection::Operation op, bool with_undo, bool no_remove) { if (!clicked_control_point) { - return; + return false; } - if (with_undo) { - begin_reversible_command (_("set selected control point")); + /* select this point and any others that it represents */ + + double y1, y2; + jack_nframes_t x1, x2; + + x1 = pixel_to_frame (clicked_control_point->get_x() - 10); + x2 = pixel_to_frame (clicked_control_point->get_x() + 10); + y1 = clicked_control_point->get_x() - 10; + y2 = clicked_control_point->get_y() + 10; + + return select_all_within (x1, x2, y1, y2, op); +} + +void +Editor::get_relevant_audio_tracks (AudioTimeAxisView& base, set& relevant_tracks) +{ + /* step one: get all selected tracks and all tracks in the relevant edit groups */ + + for (TrackSelection::iterator ti = selection->tracks.begin(); ti != selection->tracks.end(); ++ti) { + + AudioTimeAxisView* atv = dynamic_cast(*ti); + + if (!atv) { + continue; + } + + RouteGroup* group = atv->route().edit_group(); + + if (group && group->is_active()) { + + /* active group for this track, loop over all tracks and get every member of the group */ + + for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) { + + AudioTimeAxisView* tatv; + + if ((tatv = dynamic_cast (*i)) != 0) { + + if (tatv->route().edit_group() == group) { + relevant_tracks.insert (tatv); + } + } + } + + } else { + + /* no active group, or no group */ + + relevant_tracks.insert (&base); + } + } +} - if (add) { - - } else { +void +Editor::mapover_audio_tracks (slot sl) +{ + set relevant_tracks; + if (!clicked_audio_trackview) { + return; } + + get_relevant_audio_tracks (*clicked_audio_trackview, relevant_tracks); + + uint32_t sz = relevant_tracks.size(); - if (with_undo) { - commit_reversible_command (); + for (set::iterator ati = relevant_tracks.begin(); ati != relevant_tracks.end(); ++ati) { + sl (**ati, sz); } } void -Editor::set_selected_regionview_from_click (bool add, bool no_track_remove) +Editor::mapped_set_selected_regionview_from_click (AudioTimeAxisView& atv, uint32_t ignored, + AudioRegionView* basis, vector* all_equivs) { - if (!clicked_regionview) { + AudioPlaylist* pl; + vector results; + AudioRegionView* marv; + DiskStream* ds; + + if ((ds = atv.get_diskstream()) == 0) { + /* bus */ return; } - AudioTimeAxisView* atv = dynamic_cast(&clicked_regionview->get_time_axis_view()); - - if (!atv) { + if (&atv == &basis->get_time_axis_view()) { + /* looking in same track as the original */ return; } - RouteGroup* group = atv->route().edit_group(); - vector all_equivalent_regions; - if (group && group->is_active()) { + if ((pl = ds->playlist()) != 0) { + pl->get_equivalent_regions (basis->region, results); + } + + for (vector::iterator ir = results.begin(); ir != results.end(); ++ir) { + if ((marv = atv.view->find_view (**ir)) != 0) { + all_equivs->push_back (marv); + } + } +} - for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) { +bool +Editor::set_selected_regionview_from_click (bool press, Selection::Operation op, bool no_track_remove) +{ + vector all_equivalent_regions; + bool commit = false; - AudioTimeAxisView* tatv; + if (!clicked_regionview || !clicked_audio_trackview) { + return false; + } - if ((tatv = dynamic_cast (*i)) != 0) { + if (op == Selection::Toggle || op == Selection::Set) { + + mapover_audio_tracks (bind (mem_fun (*this, &Editor::mapped_set_selected_regionview_from_click), + clicked_regionview, &all_equivalent_regions)); + + + /* add clicked regionview since we skipped all other regions in the same track as the one it was in */ + + all_equivalent_regions.push_back (clicked_regionview); + + switch (op) { + case Selection::Toggle: + + if (clicked_regionview->get_selected()) { + if (press) { - if (tatv->route().edit_group() != group) { - continue; - } + /* whatever was clicked was selected already; do nothing here but allow + the button release to deselect it + */ + + button_release_can_deselect = true; + + } else { + + if (button_release_can_deselect) { + + /* just remove this one region, but only on a permitted button release */ + + selection->remove (clicked_regionview); + commit = true; + + /* no more deselect action on button release till a new press + finds an already selected object. + */ + + button_release_can_deselect = false; + } + } + + } else { + + if (press) { + /* add all the equivalent regions, but only on button press */ + + if (!all_equivalent_regions.empty()) { + commit = true; + } + + for (vector::iterator i = all_equivalent_regions.begin(); i != all_equivalent_regions.end(); ++i) { + selection->add (*i); + } + } + } + break; - AudioPlaylist* pl; - vector results; - AudioRegionView* marv; - DiskStream* ds; - - if ((ds = tatv->get_diskstream()) == 0) { - /* bus */ - continue; - } - - if ((pl = ds->playlist()) != 0) { - pl->get_equivalent_regions (clicked_regionview->region, - results); + case Selection::Set: + if (!clicked_regionview->get_selected()) { + selection->set (all_equivalent_regions); + commit = true; + } else { + /* no commit necessary: clicked on an already selected region */ + goto out; + } + break; + + default: + /* silly compiler */ + break; + } + + } else if (op == Selection::Extend) { + + list results; + jack_nframes_t last_frame; + jack_nframes_t first_frame; + + /* 1. find the last selected regionview in the track that was clicked in */ + + last_frame = 0; + first_frame = max_frames; + + for (AudioRegionSelection::iterator x = selection->audio_regions.begin(); x != selection->audio_regions.end(); ++x) { + if (&(*x)->get_time_axis_view() == &clicked_regionview->get_time_axis_view()) { + + if ((*x)->region.last_frame() > last_frame) { + last_frame = (*x)->region.last_frame(); } - - for (vector::iterator ir = results.begin(); ir != results.end(); ++ir) { - if ((marv = tatv->view->find_view (**ir)) != 0) { - all_equivalent_regions.push_back (marv); - } + + if ((*x)->region.first_frame() < first_frame) { + first_frame = (*x)->region.first_frame(); } - } } - } else { + /* 2. figure out the boundaries for our search for new objects */ - all_equivalent_regions.push_back (clicked_regionview); + switch (clicked_regionview->region.coverage (first_frame, last_frame)) { + case OverlapNone: + cerr << "no overlap, first = " << first_frame << " last = " << last_frame << " region = " + << clicked_regionview->region.first_frame() << " .. " << clicked_regionview->region.last_frame() << endl; - } - - begin_reversible_command (_("set selected regionview")); - - if (add) { + if (last_frame < clicked_regionview->region.first_frame()) { + first_frame = last_frame; + last_frame = clicked_regionview->region.last_frame(); + } else { + last_frame = first_frame; + first_frame = clicked_regionview->region.first_frame(); + } + break; - if (clicked_regionview->get_selected()) { - if (group && group->is_active() && selection->audio_regions.size() > 1) { - /* reduce selection down to just the one clicked */ - selection->set (clicked_regionview); + case OverlapExternal: + cerr << "external overlap, first = " << first_frame << " last = " << last_frame << " region = " + << clicked_regionview->region.first_frame() << " .. " << clicked_regionview->region.last_frame() << endl; + + if (last_frame < clicked_regionview->region.first_frame()) { + first_frame = last_frame; + last_frame = clicked_regionview->region.last_frame(); } else { - selection->remove (clicked_regionview); + last_frame = first_frame; + first_frame = clicked_regionview->region.first_frame(); } - } else { - selection->add (all_equivalent_regions); + break; + + case OverlapInternal: + cerr << "internal overlap, first = " << first_frame << " last = " << last_frame << " region = " + << clicked_regionview->region.first_frame() << " .. " << clicked_regionview->region.last_frame() << endl; + + if (last_frame < clicked_regionview->region.first_frame()) { + first_frame = last_frame; + last_frame = clicked_regionview->region.last_frame(); + } else { + last_frame = first_frame; + first_frame = clicked_regionview->region.first_frame(); + } + break; + + case OverlapStart: + case OverlapEnd: + /* nothing to do except add clicked region to selection, since it + overlaps with the existing selection in this track. + */ + break; } - set_selected_track_from_click (add, false, no_track_remove); + /* 2. find all selectable objects (regionviews in this case) between that one and the end of the + one that was clicked. + */ + + set relevant_tracks; - } else { + get_relevant_audio_tracks (*clicked_audio_trackview, relevant_tracks); + + for (set::iterator t = relevant_tracks.begin(); t != relevant_tracks.end(); ++t) { + (*t)->get_selectables (first_frame, last_frame, -1.0, -1.0, results); + } + + /* 3. convert to a vector of audio regions */ - // karsten wiese suggested these two lines to make - // a selected region rise to the top. but this - // leads to a mismatch between actual layering - // and visual layering. resolution required .... - // - // gnome_canvas_item_raise_to_top (clicked_regionview->get_canvas_group()); - // gnome_canvas_item_raise_to_top (clicked_regionview->get_time_axis_view().canvas_display); + vector audio_regions; + + for (list::iterator x = results.begin(); x != results.end(); ++x) { + AudioRegionView* arv; - if (clicked_regionview->get_selected()) { - /* no commit necessary: we are the one selected. */ - return; + if ((arv = dynamic_cast(*x)) != 0) { + audio_regions.push_back (arv); + } + } - } else { - - selection->set (all_equivalent_regions); - set_selected_track_from_click (add, false, false); + if (!audio_regions.empty()) { + selection->add (audio_regions); + commit = true; } } - commit_reversible_command () ; + out: + return commit; } void -Editor::set_selected_regionview_from_region_list (Region& r, bool add) +Editor::set_selected_regionview_from_region_list (Region& r, Selection::Operation op) { vector all_equivalent_regions; AudioRegion* region; @@ -3597,13 +3360,17 @@ Editor::set_selected_regionview_from_region_list (Region& r, bool add) begin_reversible_command (_("set selected regions")); - if (add) { - - selection->add (all_equivalent_regions); - - } else { - + switch (op) { + case Selection::Toggle: + /* XXX this is not correct */ + selection->toggle (all_equivalent_regions); + break; + case Selection::Set: selection->set (all_equivalent_regions); + break; + case Selection::Extend: + selection->add (all_equivalent_regions); + break; } commit_reversible_command () ; @@ -3735,21 +3502,14 @@ Editor::edit_menu_map_handler (GdkEventAny* ev) import_menu->set_name ("ArdourContextMenu"); MenuList& import_items = import_menu->items(); - import_items.push_back (MenuElem (_("... as new track"), bind (mem_fun(*this, &Editor::import_audio), true))); - import_items.push_back (MenuElem (_("... as new region"), bind (mem_fun(*this, &Editor::import_audio), false))); - - Menu* embed_menu = manage (new Menu()); - embed_menu->set_name ("ArdourContextMenu"); - MenuList& embed_items = embed_menu->items(); - - embed_items.push_back (MenuElem (_("... as new track"), bind (mem_fun(*this, &Editor::insert_sndfile), true))); - embed_items.push_back (MenuElem (_("... as new region"), mem_fun(*this, &Editor::embed_audio))); + import_items.push_back (MenuElem (_("... as new track"), bind (mem_fun(*this, &Editor::add_external_audio_action), ImportAsTrack))); + import_items.push_back (MenuElem (_("... as new region"), bind (mem_fun(*this, &Editor::add_external_audio_action), ImportAsRegion))); edit_items.push_back (MenuElem (_("Import audio (copy)"), *import_menu)); - edit_items.push_back (MenuElem (_("Embed audio (link)"), *embed_menu)); edit_items.push_back (SeparatorElem()); edit_items.push_back (MenuElem (_("Remove last capture"), mem_fun(*this, &Editor::remove_last_capture))); + if (!session->have_captured()) { edit_items.back().set_sensitive (false); } @@ -3773,49 +3533,24 @@ Editor::duplicate_dialog (bool dup_region) ArdourDialog win ("duplicate dialog"); Entry entry; Label label (_("Duplicate how many times?")); - HBox hbox; - HBox button_box; - Button ok_button (_("OK")); - Button cancel_button (_("Cancel")); - VBox vbox; - - button_box.set_spacing (7); - set_size_request_to_display_given_text (ok_button, _("Cancel"), 20, 15); // this is cancel on purpose - set_size_request_to_display_given_text (cancel_button, _("Cancel"), 20, 15); - button_box.pack_end (ok_button, false, false); - button_box.pack_end (cancel_button, false, false); - - hbox.set_spacing (5); - hbox.pack_start (label); - hbox.pack_start (entry, true, true); - - vbox.set_spacing (5); - vbox.set_border_width (5); - vbox.pack_start (hbox); - vbox.pack_start (button_box); - win.add (vbox); - win.set_position (Gtk::WIN_POS_MOUSE); - win.show_all (); + win.get_vbox()->pack_start (label); + win.add_action_widget (entry, RESPONSE_ACCEPT); + win.add_button (Stock::OK, RESPONSE_ACCEPT); + win.add_button (Stock::CANCEL, RESPONSE_CANCEL); - ok_button.signal_clicked().connect (bind (mem_fun (win, &ArdourDialog::stop), 0)); - entry.signal_activate().connect (bind (mem_fun (win, &ArdourDialog::stop), 0)); - cancel_button.signal_clicked().connect (bind (mem_fun (win, &ArdourDialog::stop), 1)); + win.set_position (WIN_POS_MOUSE); entry.set_text ("1"); set_size_request_to_display_given_text (entry, X_("12345678"), 20, 15); entry.select_region (0, entry.get_text_length()); - - win.set_position (Gtk::WIN_POS_MOUSE); - // GTK2FIX - // win.realize (); - // win.get_window()->set_decorations (Gdk::WMDecoration (Gdk::DECOR_BORDER|Gdk::DECOR_RESIZEH)); - entry.grab_focus (); - win.run (); - if (win.run_status() != 0) { + switch (win.run ()) { + case RESPONSE_ACCEPT: + break; + default: return; } @@ -3849,20 +3584,20 @@ Editor::hide_verbose_canvas_cursor () } void -Editor::set_verbose_canvas_cursor (string txt, double x, double y) +Editor::set_verbose_canvas_cursor (const string & txt, double x, double y) { /* XXX get origin of canvas relative to root window, add x and y and check compared to gdk_screen_{width,height} */ - verbose_canvas_cursor->set_property("text", txt.c_str()); - verbose_canvas_cursor->set_property("x", x); - verbose_canvas_cursor->set_property("y", y); + verbose_canvas_cursor->property_text() = txt.c_str(); + verbose_canvas_cursor->property_x() = x; + verbose_canvas_cursor->property_y() = y; } void -Editor::set_verbose_canvas_cursor_text (string txt) +Editor::set_verbose_canvas_cursor_text (const string & txt) { - verbose_canvas_cursor->set_property("text", txt.c_str()); + verbose_canvas_cursor->property_text() = txt.c_str(); } void @@ -4034,6 +3769,12 @@ Editor::time_selection_changed () (*i)->show_selection (selection->time); } } + + if (selection->time.empty()) { + ActionManager::set_sensitive (ActionManager::time_selection_sensitive_actions, false); + } else { + ActionManager::set_sensitive (ActionManager::time_selection_sensitive_actions, true); + } } void @@ -4052,27 +3793,6 @@ Editor::point_selection_changed () } } -void -Editor::run_sub_event_loop () -{ - sub_event_loop_status = 0; - Main::run (); -} - -void -Editor::finish_sub_event_loop (int status) -{ - Main::quit (); - sub_event_loop_status = status; -} - -gint -Editor::finish_sub_event_loop_on_delete (GdkEventAny *ignored, int32_t status) -{ - finish_sub_event_loop (status); - return TRUE; -} - gint Editor::mouse_select_button_release (GdkEventButton* ev) { @@ -4143,7 +3863,7 @@ Editor::ensure_float (Window& win) } void -Editor::pane_allocation_handler (Gtk::Allocation &alloc, Gtk::Paned* which) +Editor::pane_allocation_handler (Allocation &alloc, Paned* which) { /* recover or initialize pane positions. do this here rather than earlier because we don't want the positions to change the child allocations, which they seem to do. @@ -4154,7 +3874,7 @@ Editor::pane_allocation_handler (Gtk::Allocation &alloc, Gtk::Paned* which) char buf[32]; XMLNode* node = ARDOUR_UI::instance()->editor_settings(); int width, height; - static int32_t done[4] = { 0, 0, 0, 0 }; + static int32_t done; XMLNode* geometry; if ((geometry = find_named_node (*node, "geometry")) == 0) { @@ -4165,89 +3885,38 @@ Editor::pane_allocation_handler (Gtk::Allocation &alloc, Gtk::Paned* which) height = atoi(geometry->property("y_size")->value()); } - if (which == static_cast (&track_list_canvas_pane)) { - - if (done[0]) { - return; - } - - if (!geometry || (prop = geometry->property("track_list_canvas_pane_pos")) == 0) { - pos = 75; - snprintf (buf, sizeof(buf), "%d", pos); - } else { - pos = atoi (prop->value()); - } - - if ((done[0] = GTK_WIDGET(track_list_canvas_pane.gobj())->allocation.width > pos)) { - track_list_canvas_pane.set_position (pos); - } - - } else if (which == static_cast (&canvas_region_list_pane)) { - - if (done[1]) { - return; - } - - if (!geometry || (prop = geometry->property("canvas_region_list_pane_pos")) == 0) { - pos = width - (95 * 2); - snprintf (buf, sizeof(buf), "%d", pos); - } else { - pos = atoi (prop->value()); - } - - if ((done[1] = GTK_WIDGET(canvas_region_list_pane.gobj())->allocation.width > pos)) { - canvas_region_list_pane.set_position (pos); - } - - } else if (which == static_cast (&route_group_vpane)) { + if (which == static_cast (&edit_pane)) { - if (done[2]) { + if (done) { return; } - if (!geometry || (prop = geometry->property("route_group_pane_pos")) == 0) { - pos = width - (95 * 2); + if (!geometry || (prop = geometry->property ("edit_pane_pos")) == 0) { + /* initial allocation is 90% to canvas, 10% to notebook */ + pos = (int) floor (alloc.get_width() * 0.90f); snprintf (buf, sizeof(buf), "%d", pos); } else { pos = atoi (prop->value()); } - - if ((done[2] = GTK_WIDGET(route_group_vpane.gobj())->allocation.height > pos)) { - route_group_vpane.set_position (pos); - } - - } else if (which == static_cast (®ion_selection_vpane)) { - - if (done[3]) { - return; - } - - if (!geometry || (prop = geometry->property("region_selection_pane_pos")) == 0) { - pos = width - (95 * 2); - snprintf (buf, sizeof(buf), "%d", pos); - } else { - pos = atoi (prop->value()); - } - - if ((done[3] = GTK_WIDGET(region_selection_vpane.gobj())->allocation.height > pos)) { - region_selection_vpane.set_position (pos); + + if ((done = GTK_WIDGET(edit_pane.gobj())->allocation.width > pos)) { + edit_pane.set_position (pos); + pre_maximal_pane_position = pos; } } } void -Editor::detach_tearoff (Gtk::Box* b, Gtk::Window* w) +Editor::detach_tearoff (Box* b, Window* w) { if (tools_tearoff->torn_off() && mouse_mode_tearoff->torn_off()) { top_hbox.remove (toolbar_frame); } - - ensure_float (*w); } void -Editor::reattach_tearoff (Gtk::Box* b, Gtk::Window* w, int32_t n) +Editor::reattach_tearoff (Box* b, Window* w, int32_t n) { if (toolbar_frame.get_parent() == 0) { top_hbox.pack_end (toolbar_frame); @@ -4268,6 +3937,16 @@ Editor::set_show_measures (bool yn) } } +void +Editor::toggle_follow_playhead () +{ + RefPtr act = ActionManager::get_action (X_("Editor"), X_("toggle-follow-playhead")); + if (act) { + RefPtr tact = RefPtr::cast_dynamic(act); + set_follow_playhead (tact->get_active()); + } +} + void Editor::set_follow_playhead (bool yn) { @@ -4300,17 +3979,15 @@ Editor::edit_xfade (Crossfade* xfade) ensure_float (cew); - cew.ok_button.signal_clicked().connect (bind (mem_fun (cew, &ArdourDialog::stop), 1)); - cew.cancel_button.signal_clicked().connect (bind (mem_fun (cew, &ArdourDialog::stop), 0)); - // GTK2FIX - // cew.signal_delete_event().connect (mem_fun (cew, &ArdourDialog::wm_doi_event_stop)); - - cew.run (); - - if (cew.run_status() == 1) { - cew.apply (); - xfade->StateChanged (Change (~0)); + switch (cew.run ()) { + case RESPONSE_ACCEPT: + break; + default: + return; } + + cew.apply (); + xfade->StateChanged (Change (~0)); } PlaylistSelector& @@ -4334,7 +4011,7 @@ void Editor::end_location_changed (Location* location) { ENSURE_GUI_THREAD (bind (mem_fun(*this, &Editor::end_location_changed), location)); - track_canvas_scroller.get_hadjustment()->set_upper (location->end() / frames_per_unit); + reset_scrolling_region (); } int @@ -4345,56 +4022,30 @@ Editor::playlist_deletion_dialog (Playlist* pl) "If left alone, no audio files used by it will be cleaned.\n" "If deleted, audio files used by it alone by will cleaned."), pl->name())); - HBox button_box; - Button del_button (_("Delete playlist")); - Button keep_button (_("Keep playlist")); - Button abort_button (_("Cancel cleanup")); - VBox vbox; - - button_box.set_spacing (7); - button_box.set_homogeneous (true); - button_box.pack_end (del_button, false, false); - button_box.pack_end (keep_button, false, false); - button_box.pack_end (abort_button, false, false); - - vbox.set_spacing (5); - vbox.set_border_width (5); - vbox.pack_start (label); - vbox.pack_start (button_box); - - dialog.add (vbox); - dialog.set_position (Gtk::WIN_POS_CENTER); - dialog.show_all (); - del_button.signal_clicked().connect (bind (mem_fun (dialog, &ArdourDialog::stop), 0)); - keep_button.signal_clicked().connect (bind (mem_fun (dialog, &ArdourDialog::stop), 1)); - abort_button.signal_clicked().connect (bind (mem_fun (dialog, &ArdourDialog::stop), 2)); + dialog.set_position (WIN_POS_CENTER); + dialog.get_vbox()->pack_start (label); - // GTK2FIX - // dialog.realize (); - // dialog.get_window()->set_decorations (Gdk::WMDecoration (Gdk::DECOR_BORDER|Gdk::DECOR_RESIZEH)); + dialog.add_button (_("Delete playlist"), RESPONSE_ACCEPT); + dialog.add_button (_("Keep playlist"), RESPONSE_CANCEL); + dialog.add_button (_("Cancel"), RESPONSE_CANCEL); - dialog.run (); - - switch (dialog.run_status()) { - case 1: - /* keep the playlist */ - return 1; - break; - case 0: + switch (dialog.run ()) { + case RESPONSE_ACCEPT: /* delete the playlist */ return 0; break; - case 2: - /* abort cleanup */ - return -1; + + case RESPONSE_REJECT: + /* keep the playlist */ + return 1; break; + default: break; } - /* keep the playlist */ - return 1; + return -1; } bool @@ -4419,18 +4070,6 @@ Editor::prepare_for_cleanup () selection->clear_playlists (); } -void -Editor::init_colormap () -{ - for (size_t x = 0; x < sizeof (color_id_strs) / sizeof (color_id_strs[0]); ++x) { - pair newpair; - - newpair.first = (ColorID) x; - newpair.second = rgba_from_style (enum2str (newpair.first), 0, 0, 0, 255); - color_map.insert (newpair); - } -} - Location* Editor::transport_loop_location() { @@ -4450,3 +4089,202 @@ Editor::transport_punch_location() return 0; } } + +bool +Editor::control_layout_scroll (GdkEventScroll* ev) +{ + switch (ev->direction) { + case GDK_SCROLL_UP: + scroll_tracks_up_line (); + return true; + break; + + case GDK_SCROLL_DOWN: + scroll_tracks_down_line (); + return true; + + default: + /* no left/right handling yet */ + break; + } + + return false; +} + +void +Editor::snapshot_display_selection_changed () +{ + if (snapshot_display.get_selection()->count_selected_rows() > 0) { + + TreeModel::iterator i = snapshot_display.get_selection()->get_selected(); + + Glib::ustring snap_name = (*i)[snapshot_display_columns.real_name]; + + if (snap_name.length() == 0) { + return; + } + + if (session->snap_name() == snap_name) { + return; + } + + ARDOUR_UI::instance()->load_session(session->path(), string (snap_name)); + } +} + +bool +Editor::snapshot_display_button_press (GdkEventButton* ev) +{ + return false; +} + +void +Editor::redisplay_snapshots () +{ + if (session == 0) { + return; + } + + vector* states; + + if ((states = session->possible_states()) == 0) { + return; + } + + snapshot_display_model->clear (); + + for (vector::iterator i = states->begin(); i != states->end(); ++i) { + string statename = *(*i); + TreeModel::Row row = *(snapshot_display_model->append()); + row[snapshot_display_columns.visible_name] = statename; + row[snapshot_display_columns.real_name] = statename; + } + + delete states; +} + +void +Editor::session_state_saved (string snap_name) +{ + ENSURE_GUI_THREAD (bind (mem_fun(*this, &Editor::session_state_saved), snap_name)); + redisplay_snapshots (); +} + +void +Editor::maximise_editing_space () +{ + mouse_mode_tearoff->set_visible (false); + tools_tearoff->set_visible (false); + + pre_maximal_pane_position = edit_pane.get_position(); + edit_pane.set_position (edit_pane.get_width()); + + fullscreen(); +} + +void +Editor::restore_editing_space () +{ + mouse_mode_tearoff->set_visible (true); + tools_tearoff->set_visible (true); + edit_pane.set_position (pre_maximal_pane_position); + + unfullscreen(); +} + +void +Editor::new_playlists () +{ + begin_reversible_command (_("new playlists")); + mapover_audio_tracks (mem_fun (*this, &Editor::mapped_use_new_playlist)); + commit_reversible_command (); +} + +void +Editor::copy_playlists () +{ + begin_reversible_command (_("copy playlists")); + mapover_audio_tracks (mem_fun (*this, &Editor::mapped_use_copy_playlist)); + commit_reversible_command (); +} + +void +Editor::clear_playlists () +{ + begin_reversible_command (_("clear playlists")); + mapover_audio_tracks (mem_fun (*this, &Editor::mapped_clear_playlist)); + commit_reversible_command (); +} + +void +Editor::mapped_use_new_playlist (AudioTimeAxisView& atv, uint32_t sz) +{ + atv.use_new_playlist (sz > 1 ? false : true); +} + +void +Editor::mapped_use_copy_playlist (AudioTimeAxisView& atv, uint32_t sz) +{ + atv.use_copy_playlist (sz > 1 ? false : true); +} + +void +Editor::mapped_clear_playlist (AudioTimeAxisView& atv, uint32_t sz) +{ + atv.clear_playlist (); +} + +bool +Editor::on_key_press_event (GdkEventKey* ev) +{ + return key_press_focus_accelerator_handler (*this, ev); +} + +void +Editor::update_layering_model () +{ + RefPtr act; + + switch (session->get_layer_model()) { + case Session::LaterHigher: + act = ActionManager::get_action (X_("Editor"), X_("LayerLaterHigher")); + break; + case Session::MoveAddHigher: + act = ActionManager::get_action (X_("Editor"), X_("LayerMoveAddHigher")); + break; + case Session::AddHigher: + act = ActionManager::get_action (X_("Editor"), X_("LayerAddHigher")); + break; + } + + if (act) { + RefPtr ract = RefPtr::cast_dynamic(act); + if (ract && !ract->get_active()) { + ract->set_active (true); + } + } +} + + +void +Editor::update_crossfade_model () +{ + RefPtr act; + + switch (session->get_xfade_model()) { + case FullCrossfade: + act = ActionManager::get_action (X_("Editor"), X_("CrossfadesFull")); + break; + case ShortCrossfade: + act = ActionManager::get_action (X_("Editor"), X_("CrossfadesShort")); + break; + } + + if (act) { + RefPtr ract = RefPtr::cast_dynamic(act); + if (ract && !ract->get_active()) { + ract->set_active (true); + } + } +} +