+
+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<string*>* states;
+
+ if ((states = session->possible_states()) == 0) {
+ return;
+ }
+
+ snapshot_display_model->clear ();
+
+ for (vector<string*>::iterator i = states->begin(); i != states->end(); ++i) {
+ string statename = *(*i);
+ TreeModel::Row row = *(snapshot_display_model->append());
+
+ /* this lingers on in case we ever want to change the visible
+ name of the snapshot.
+ */
+
+ string display_name;
+ display_name = statename;
+
+ if (statename == session->snap_name()) {
+ snapshot_display.get_selection()->select(row);
+ }
+
+ row[snapshot_display_columns.visible_name] = display_name;
+ 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 ()
+{
+ initial_ruler_update_required = true;
+
+ mouse_mode_tearoff->set_visible (false);
+ tools_tearoff->set_visible (false);
+
+ pre_maximal_pane_position = edit_pane.get_position();
+ pre_maximal_editor_width = this->get_width();
+
+ if(post_maximal_pane_position == 0) {
+ post_maximal_pane_position = edit_pane.get_width();
+ }
+
+
+ fullscreen();
+ if(post_maximal_editor_width) {
+ edit_pane.set_position (post_maximal_pane_position -
+ abs(post_maximal_editor_width - pre_maximal_editor_width));
+ } else {
+ edit_pane.set_position (post_maximal_pane_position);
+ }
+}
+
+void
+Editor::restore_editing_space ()
+{
+ initial_ruler_update_required = true;
+
+ // user changed width of pane during fullscreen
+ if(post_maximal_pane_position != edit_pane.get_position()) {
+ post_maximal_pane_position = edit_pane.get_position();
+ }
+
+ unfullscreen();
+
+ mouse_mode_tearoff->set_visible (true);
+ tools_tearoff->set_visible (true);
+ post_maximal_editor_width = this->get_width();
+
+
+ edit_pane.set_position (
+ pre_maximal_pane_position + abs(this->get_width() - pre_maximal_editor_width)
+ );
+}
+
+void
+Editor::new_playlists ()
+{
+ begin_reversible_command (_("new playlists"));
+ mapover_tracks (mem_fun (*this, &Editor::mapped_use_new_playlist));
+ commit_reversible_command ();
+}
+
+void
+Editor::copy_playlists ()
+{
+ begin_reversible_command (_("copy playlists"));
+ mapover_tracks (mem_fun (*this, &Editor::mapped_use_copy_playlist));
+ commit_reversible_command ();
+}
+
+void
+Editor::clear_playlists ()
+{
+ begin_reversible_command (_("clear playlists"));
+ mapover_tracks (mem_fun (*this, &Editor::mapped_clear_playlist));
+ commit_reversible_command ();
+}
+
+void
+Editor::mapped_use_new_playlist (RouteTimeAxisView& atv, uint32_t sz)
+{
+ atv.use_new_playlist (sz > 1 ? false : true);
+}
+
+void
+Editor::mapped_use_copy_playlist (RouteTimeAxisView& atv, uint32_t sz)
+{
+ atv.use_copy_playlist (sz > 1 ? false : true);
+}
+
+void
+Editor::mapped_clear_playlist (RouteTimeAxisView& 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::reset_x_origin (nframes_t frame)
+{
+ queue_visual_change (frame);
+}
+
+void
+Editor::reset_zoom (double fpu)
+{
+ queue_visual_change (fpu);
+}
+
+void
+Editor::reposition_and_zoom (nframes_t frame, double fpu)
+{
+ reset_x_origin (frame);
+ reset_zoom (fpu);
+}
+
+void
+Editor::set_frames_per_unit (double fpu)
+{
+ nframes_t frames;
+
+ /* this is the core function that controls the zoom level of the canvas. it is called
+ whenever one or more calls are made to reset_zoom(). it executes in an idle handler.
+ */
+
+ if (fpu == frames_per_unit) {
+ return;
+ }
+
+ if (fpu < 2.0) {
+ fpu = 2.0;
+ }
+
+ // convert fpu to frame count
+
+ frames = (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.
+ */
+
+ if (max_frames / fpu < 800.0) {
+ return;
+ }
+
+ if (fpu == frames_per_unit) {
+ return;
+ }
+
+ frames_per_unit = fpu;
+
+ if (frames != zoom_range_clock.current_duration()) {
+ zoom_range_clock.set (frames);
+ }
+
+ if (mouse_mode == MouseRange && selection->time.start () != selection->time.end_frame ()) {
+ 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);
+
+ instant_save ();
+}
+
+void
+Editor::canvas_horizontally_scrolled ()
+{
+ /* this is the core function that controls horizontal scrolling of the canvas. it is called
+ whenever the horizontal_adjustment emits its "value_changed" signal. it executes in an
+ idle handler.
+ */
+
+ leftmost_frame = (nframes_t) floor (horizontal_adjustment.get_value() * frames_per_unit);
+ nframes_t rightmost_frame = leftmost_frame + current_page_frames ();
+
+ if (rightmost_frame > last_canvas_frame) {
+ last_canvas_frame = rightmost_frame;
+ reset_scrolling_region ();
+ }
+
+ update_fixed_rulers ();
+ tempo_map_changed (Change (0));
+}
+
+void
+Editor::queue_visual_change (nframes_t where)
+{
+ pending_visual_change.pending = VisualChange::Type (pending_visual_change.pending | VisualChange::TimeOrigin);
+ pending_visual_change.time_origin = where;
+
+ if (pending_visual_change.idle_handler_id < 0) {
+ pending_visual_change.idle_handler_id = g_idle_add (_idle_visual_changer, this);
+ }
+}
+
+void
+Editor::queue_visual_change (double fpu)
+{
+ pending_visual_change.pending = VisualChange::Type (pending_visual_change.pending | VisualChange::ZoomLevel);
+ pending_visual_change.frames_per_unit = fpu;
+
+ if (pending_visual_change.idle_handler_id < 0) {
+ pending_visual_change.idle_handler_id = g_idle_add_full (G_PRIORITY_HIGH_IDLE, _idle_visual_changer, this, 0);
+ }
+}
+
+int
+Editor::_idle_visual_changer (void* arg)
+{
+ return static_cast<Editor*>(arg)->idle_visual_changer ();
+}
+
+int
+Editor::idle_visual_changer ()
+{
+ VisualChange::Type p = pending_visual_change.pending;
+
+ pending_visual_change.pending = (VisualChange::Type) 0;
+ pending_visual_change.idle_handler_id = -1;
+
+ if (p & VisualChange::ZoomLevel) {
+ set_frames_per_unit (pending_visual_change.frames_per_unit);
+ }
+
+ if (p & VisualChange::TimeOrigin) {
+ if (pending_visual_change.time_origin != leftmost_frame) {
+ horizontal_adjustment.set_value (pending_visual_change.time_origin/frames_per_unit);
+ /* the signal handler will do the rest */
+ } else {
+ update_fixed_rulers();
+ tempo_map_changed (Change (0));
+ }
+ }
+
+ return 0;
+}
+
+struct EditorOrderTimeAxisSorter {
+ bool operator() (const TimeAxisView* a, const TimeAxisView* b) const {
+ return a->order < b->order;
+ }
+};
+
+void
+Editor::sort_track_selection ()
+{
+ EditorOrderTimeAxisSorter cmp;
+ selection->tracks.sort (cmp);
+}
+