mirror of
https://github.com/Ardour/ardour.git
synced 2025-12-19 13:16:27 +01:00
refactor editor-y zooms into EditingContext
This commit is contained in:
parent
c2b1748de7
commit
a6ca9be006
9 changed files with 590 additions and 547 deletions
|
|
@ -242,3 +242,21 @@ CueEditor::history_changed ()
|
||||||
update_undo_redo_actions (_history);
|
update_undo_redo_actions (_history);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::pair<Temporal::timepos_t,Temporal::timepos_t>
|
||||||
|
CueEditor::max_zoom_extent() const
|
||||||
|
{
|
||||||
|
return std::make_pair (Temporal::timepos_t (Temporal::Beats()), Temporal::timepos_t (Temporal::Beats (32, 0)));
|
||||||
|
}
|
||||||
|
|
||||||
|
Temporal::timepos_t
|
||||||
|
CueEditor::_get_preferred_edit_position (Editing::EditIgnoreOption ignore, bool from_context_menu, bool from_outside_canvas)
|
||||||
|
{
|
||||||
|
samplepos_t where;
|
||||||
|
bool in_track_canvas = false;
|
||||||
|
|
||||||
|
if (!mouse_sample (where, in_track_canvas)) {
|
||||||
|
return Temporal::timepos_t (0);
|
||||||
|
}
|
||||||
|
|
||||||
|
return Temporal::timepos_t (where);
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -104,5 +104,9 @@ class CueEditor : public EditingContext, public PBD::HistoryOwner, public sigc::
|
||||||
|
|
||||||
void do_undo (uint32_t n);
|
void do_undo (uint32_t n);
|
||||||
void do_redo (uint32_t n);
|
void do_redo (uint32_t n);
|
||||||
|
|
||||||
|
std::pair<Temporal::timepos_t,Temporal::timepos_t> max_zoom_extent() const;
|
||||||
|
|
||||||
|
Temporal::timepos_t _get_preferred_edit_position (Editing::EditIgnoreOption, bool use_context_click, bool from_outside_canvas);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -20,6 +20,7 @@
|
||||||
|
|
||||||
#include "pbd/error.h"
|
#include "pbd/error.h"
|
||||||
#include "pbd/stacktrace.h"
|
#include "pbd/stacktrace.h"
|
||||||
|
#include "pbd/unwind.h"
|
||||||
|
|
||||||
#include "ardour/legatize.h"
|
#include "ardour/legatize.h"
|
||||||
#include "ardour/midi_region.h"
|
#include "ardour/midi_region.h"
|
||||||
|
|
@ -112,6 +113,7 @@ Glib::RefPtr<Gtk::Action> EditingContext::alternate_alternate_redo_action;
|
||||||
EditingContext::EditingContext (std::string const & name)
|
EditingContext::EditingContext (std::string const & name)
|
||||||
: rubberband_rect (0)
|
: rubberband_rect (0)
|
||||||
, _name (name)
|
, _name (name)
|
||||||
|
, within_track_canvas (false)
|
||||||
, pre_internal_grid_type (GridTypeBeat)
|
, pre_internal_grid_type (GridTypeBeat)
|
||||||
, pre_internal_snap_mode (SnapOff)
|
, pre_internal_snap_mode (SnapOff)
|
||||||
, internal_grid_type (GridTypeBeat)
|
, internal_grid_type (GridTypeBeat)
|
||||||
|
|
@ -2762,3 +2764,392 @@ void
|
||||||
EditingContext::follow_playhead_clicked ()
|
EditingContext::follow_playhead_clicked ()
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
EditingContext::cycle_zoom_focus ()
|
||||||
|
{
|
||||||
|
switch (zoom_focus) {
|
||||||
|
case ZoomFocusLeft:
|
||||||
|
set_zoom_focus (ZoomFocusRight);
|
||||||
|
break;
|
||||||
|
case ZoomFocusRight:
|
||||||
|
set_zoom_focus (ZoomFocusCenter);
|
||||||
|
break;
|
||||||
|
case ZoomFocusCenter:
|
||||||
|
set_zoom_focus (ZoomFocusPlayhead);
|
||||||
|
break;
|
||||||
|
case ZoomFocusPlayhead:
|
||||||
|
set_zoom_focus (ZoomFocusMouse);
|
||||||
|
break;
|
||||||
|
case ZoomFocusMouse:
|
||||||
|
set_zoom_focus (ZoomFocusEdit);
|
||||||
|
break;
|
||||||
|
case ZoomFocusEdit:
|
||||||
|
set_zoom_focus (ZoomFocusLeft);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
EditingContext::temporal_zoom_step_mouse_focus_scale (bool zoom_out, double scale)
|
||||||
|
{
|
||||||
|
PBD::Unwinder<Editing::ZoomFocus> zf (zoom_focus, Editing::ZoomFocusMouse);
|
||||||
|
temporal_zoom_step_scale (zoom_out, scale);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
EditingContext::temporal_zoom_step_mouse_focus (bool zoom_out)
|
||||||
|
{
|
||||||
|
temporal_zoom_step_mouse_focus_scale (zoom_out, 2.0);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
EditingContext::temporal_zoom_step (bool zoom_out)
|
||||||
|
{
|
||||||
|
temporal_zoom_step_scale (zoom_out, 2.0);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
EditingContext::temporal_zoom_step_scale (bool zoom_out, double scale)
|
||||||
|
{
|
||||||
|
ENSURE_GUI_THREAD (*this, &EditingContext::temporal_zoom_step, zoom_out, scale)
|
||||||
|
|
||||||
|
samplecnt_t nspp = samples_per_pixel;
|
||||||
|
|
||||||
|
if (zoom_out) {
|
||||||
|
nspp *= scale;
|
||||||
|
if (nspp == samples_per_pixel) {
|
||||||
|
nspp *= 2.0;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
nspp /= scale;
|
||||||
|
if (nspp == samples_per_pixel) {
|
||||||
|
nspp /= 2.0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//zoom-behavior-tweaks
|
||||||
|
//limit our maximum zoom to the session gui extents value
|
||||||
|
std::pair<timepos_t, timepos_t> ext = max_zoom_extent();
|
||||||
|
samplecnt_t session_extents_pp = (ext.second.samples() - ext.first.samples()) / _visible_canvas_width;
|
||||||
|
if (nspp > session_extents_pp) {
|
||||||
|
nspp = session_extents_pp;
|
||||||
|
}
|
||||||
|
|
||||||
|
temporal_zoom (nspp);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
EditingContext::temporal_zoom (samplecnt_t spp)
|
||||||
|
{
|
||||||
|
if (!_session) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
samplepos_t current_page = current_page_samples();
|
||||||
|
samplepos_t current_leftmost = _leftmost_sample;
|
||||||
|
samplepos_t current_rightmost;
|
||||||
|
samplepos_t current_center;
|
||||||
|
samplepos_t new_page_size;
|
||||||
|
samplepos_t half_page_size;
|
||||||
|
samplepos_t leftmost_after_zoom = 0;
|
||||||
|
samplepos_t where;
|
||||||
|
bool in_track_canvas;
|
||||||
|
bool use_mouse_sample = true;
|
||||||
|
samplecnt_t nspp;
|
||||||
|
double l;
|
||||||
|
|
||||||
|
if (spp == samples_per_pixel) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Imposing an arbitrary limit to zoom out as too much zoom out produces
|
||||||
|
// segfaults for lack of memory. If somebody decides this is not high enough I
|
||||||
|
// believe it can be raisen to higher values but some limit must be in place.
|
||||||
|
//
|
||||||
|
// This constant represents 1 day @ 48kHz on a 1600 pixel wide display
|
||||||
|
// all of which is used for the editor track displays. The whole day
|
||||||
|
// would be 4147200000 samples, so 2592000 samples per pixel.
|
||||||
|
|
||||||
|
nspp = std::min (spp, (samplecnt_t) 2592000);
|
||||||
|
nspp = std::max ((samplecnt_t) 1, nspp);
|
||||||
|
|
||||||
|
new_page_size = (samplepos_t) floor (_visible_canvas_width * nspp);
|
||||||
|
half_page_size = new_page_size / 2;
|
||||||
|
|
||||||
|
Editing::ZoomFocus zf = effective_zoom_focus();
|
||||||
|
|
||||||
|
switch (zf) {
|
||||||
|
case ZoomFocusLeft:
|
||||||
|
leftmost_after_zoom = current_leftmost;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case ZoomFocusRight:
|
||||||
|
current_rightmost = _leftmost_sample + current_page;
|
||||||
|
if (current_rightmost < new_page_size) {
|
||||||
|
leftmost_after_zoom = 0;
|
||||||
|
} else {
|
||||||
|
leftmost_after_zoom = current_rightmost - new_page_size;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case ZoomFocusCenter:
|
||||||
|
current_center = current_leftmost + (current_page/2);
|
||||||
|
if (current_center < half_page_size) {
|
||||||
|
leftmost_after_zoom = 0;
|
||||||
|
} else {
|
||||||
|
leftmost_after_zoom = current_center - half_page_size;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case ZoomFocusPlayhead:
|
||||||
|
/* centre playhead */
|
||||||
|
l = _session->transport_sample() - (new_page_size * 0.5);
|
||||||
|
|
||||||
|
if (l < 0) {
|
||||||
|
leftmost_after_zoom = 0;
|
||||||
|
} else if (l > max_samplepos) {
|
||||||
|
leftmost_after_zoom = max_samplepos - new_page_size;
|
||||||
|
} else {
|
||||||
|
leftmost_after_zoom = (samplepos_t) l;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case ZoomFocusMouse:
|
||||||
|
/* try to keep the mouse over the same point in the display */
|
||||||
|
|
||||||
|
if (_drags->active()) {
|
||||||
|
where = _drags->current_pointer_sample ();
|
||||||
|
} else if (!mouse_sample (where, in_track_canvas)) {
|
||||||
|
use_mouse_sample = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (use_mouse_sample) {
|
||||||
|
l = - ((new_page_size * ((where - current_leftmost)/(double)current_page)) - where);
|
||||||
|
|
||||||
|
if (l < 0) {
|
||||||
|
leftmost_after_zoom = 0;
|
||||||
|
} else if (l > max_samplepos) {
|
||||||
|
leftmost_after_zoom = max_samplepos - new_page_size;
|
||||||
|
} else {
|
||||||
|
leftmost_after_zoom = (samplepos_t) l;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
/* use playhead instead */
|
||||||
|
where = _session->transport_sample();
|
||||||
|
|
||||||
|
if (where < half_page_size) {
|
||||||
|
leftmost_after_zoom = 0;
|
||||||
|
} else {
|
||||||
|
leftmost_after_zoom = where - half_page_size;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case ZoomFocusEdit:
|
||||||
|
/* try to keep the edit point in the same place */
|
||||||
|
where = get_preferred_edit_position ().samples();
|
||||||
|
{
|
||||||
|
double l = - ((new_page_size * ((where - current_leftmost)/(double)current_page)) - where);
|
||||||
|
|
||||||
|
if (l < 0) {
|
||||||
|
leftmost_after_zoom = 0;
|
||||||
|
} else if (l > max_samplepos) {
|
||||||
|
leftmost_after_zoom = max_samplepos - new_page_size;
|
||||||
|
} else {
|
||||||
|
leftmost_after_zoom = (samplepos_t) l;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
// leftmost_after_zoom = min (leftmost_after_zoom, _session->current_end_sample());
|
||||||
|
|
||||||
|
reposition_and_zoom (leftmost_after_zoom, nspp);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
EditingContext::calc_extra_zoom_edges (samplepos_t &start, samplepos_t &end)
|
||||||
|
{
|
||||||
|
/* this func helps make sure we leave a little space
|
||||||
|
at each end of the editor so that the zoom doesn't fit the region
|
||||||
|
precisely to the screen.
|
||||||
|
*/
|
||||||
|
|
||||||
|
GdkScreen* screen = gdk_screen_get_default ();
|
||||||
|
const gint pixwidth = gdk_screen_get_width (screen);
|
||||||
|
const gint mmwidth = gdk_screen_get_width_mm (screen);
|
||||||
|
const double pix_per_mm = (double) pixwidth/ (double) mmwidth;
|
||||||
|
const double one_centimeter_in_pixels = pix_per_mm * 10.0;
|
||||||
|
|
||||||
|
const samplepos_t range = end - start;
|
||||||
|
const samplecnt_t new_fpp = (samplecnt_t) ceil ((double) range / (double) _visible_canvas_width);
|
||||||
|
const samplepos_t extra_samples = (samplepos_t) floor (one_centimeter_in_pixels * new_fpp);
|
||||||
|
|
||||||
|
if (start > extra_samples) {
|
||||||
|
start -= extra_samples;
|
||||||
|
} else {
|
||||||
|
start = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (max_samplepos - extra_samples > end) {
|
||||||
|
end += extra_samples;
|
||||||
|
} else {
|
||||||
|
end = max_samplepos;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
EditingContext::temporal_zoom_by_sample (samplepos_t start, samplepos_t end)
|
||||||
|
{
|
||||||
|
if (!_session) return;
|
||||||
|
|
||||||
|
if ((start == 0 && end == 0) || end < start) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
samplepos_t range = end - start;
|
||||||
|
|
||||||
|
const samplecnt_t new_fpp = (samplecnt_t) ceil ((double) range / (double) _visible_canvas_width);
|
||||||
|
|
||||||
|
samplepos_t new_page = range;
|
||||||
|
samplepos_t middle = (samplepos_t) floor ((double) start + ((double) range / 2.0f));
|
||||||
|
samplepos_t new_leftmost = (samplepos_t) floor ((double) middle - ((double) new_page / 2.0f));
|
||||||
|
|
||||||
|
if (new_leftmost > middle) {
|
||||||
|
new_leftmost = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (new_leftmost < 0) {
|
||||||
|
new_leftmost = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
reposition_and_zoom (new_leftmost, new_fpp);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
EditingContext::temporal_zoom_to_sample (bool coarser, samplepos_t sample)
|
||||||
|
{
|
||||||
|
if (!_session) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
samplecnt_t range_before = sample - _leftmost_sample;
|
||||||
|
samplecnt_t new_spp;
|
||||||
|
|
||||||
|
if (coarser) {
|
||||||
|
if (samples_per_pixel <= 1) {
|
||||||
|
new_spp = 2;
|
||||||
|
} else {
|
||||||
|
new_spp = samples_per_pixel + (samples_per_pixel/2);
|
||||||
|
}
|
||||||
|
range_before += range_before/2;
|
||||||
|
} else {
|
||||||
|
if (samples_per_pixel >= 1) {
|
||||||
|
new_spp = samples_per_pixel - (samples_per_pixel/2);
|
||||||
|
} else {
|
||||||
|
/* could bail out here since we cannot zoom any finer,
|
||||||
|
but leave that to the equality test below
|
||||||
|
*/
|
||||||
|
new_spp = samples_per_pixel;
|
||||||
|
}
|
||||||
|
|
||||||
|
range_before -= range_before/2;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (new_spp == samples_per_pixel) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* zoom focus is automatically taken as @p sample when this
|
||||||
|
method is used.
|
||||||
|
*/
|
||||||
|
|
||||||
|
samplepos_t new_leftmost = sample - (samplepos_t)range_before;
|
||||||
|
|
||||||
|
if (new_leftmost > sample) {
|
||||||
|
new_leftmost = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (new_leftmost < 0) {
|
||||||
|
new_leftmost = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
reposition_and_zoom (new_leftmost, new_spp);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool
|
||||||
|
EditingContext::mouse_sample (samplepos_t& where, bool& in_track_canvas) const
|
||||||
|
{
|
||||||
|
/* gdk_window_get_pointer() has X11's XQueryPointer semantics in that it only
|
||||||
|
* pays attentions to subwindows. this means that menu windows are ignored, and
|
||||||
|
* if the pointer is in a menu, the return window from the call will be the
|
||||||
|
* the regular subwindow *under* the menu.
|
||||||
|
*
|
||||||
|
* this matters quite a lot if the pointer is moving around in a menu that overlaps
|
||||||
|
* the track canvas because we will believe that we are within the track canvas
|
||||||
|
* when we are not. therefore, we track enter/leave events for the track canvas
|
||||||
|
* and allow that to override the result of gdk_window_get_pointer().
|
||||||
|
*/
|
||||||
|
|
||||||
|
if (!within_track_canvas) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
int x, y;
|
||||||
|
Glib::RefPtr<Gdk::Window> canvas_window = const_cast<EditingContext*>(this)->get_canvas()->get_window();
|
||||||
|
|
||||||
|
if (!canvas_window) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
Glib::RefPtr<const Gdk::Window> pointer_window = Gdk::Display::get_default()->get_window_at_pointer (x, y);
|
||||||
|
|
||||||
|
if (!pointer_window) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (pointer_window != canvas_window) {
|
||||||
|
in_track_canvas = false;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
in_track_canvas = true;
|
||||||
|
|
||||||
|
GdkEvent event;
|
||||||
|
event.type = GDK_BUTTON_RELEASE;
|
||||||
|
event.button.x = x;
|
||||||
|
event.button.y = y;
|
||||||
|
|
||||||
|
where = window_event_sample (&event, 0, 0);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
samplepos_t
|
||||||
|
EditingContext::window_event_sample (GdkEvent const * event, double* pcx, double* pcy) const
|
||||||
|
{
|
||||||
|
ArdourCanvas::Duple d;
|
||||||
|
|
||||||
|
if (!gdk_event_get_coords (event, &d.x, &d.y)) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* event coordinates are in window units, so convert to canvas
|
||||||
|
*/
|
||||||
|
|
||||||
|
d = get_canvas()->window_to_canvas (d);
|
||||||
|
|
||||||
|
if (pcx) {
|
||||||
|
*pcx = d.x;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (pcy) {
|
||||||
|
*pcy = d.y;
|
||||||
|
}
|
||||||
|
|
||||||
|
return pixel_to_sample (d.x);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -146,6 +146,12 @@ class EditingContext : public ARDOUR::SessionHandlePtr, public AxisViewProvider
|
||||||
/** @return true if the editor is following the playhead */
|
/** @return true if the editor is following the playhead */
|
||||||
bool follow_playhead () const { return _follow_playhead; }
|
bool follow_playhead () const { return _follow_playhead; }
|
||||||
|
|
||||||
|
Temporal::timepos_t get_preferred_edit_position (Editing::EditIgnoreOption eio = Editing::EDIT_IGNORE_NONE,
|
||||||
|
bool use_context_click = false,
|
||||||
|
bool from_outside_canvas = false) {
|
||||||
|
return _get_preferred_edit_position (eio, use_context_click, from_outside_canvas);
|
||||||
|
}
|
||||||
|
|
||||||
virtual void instant_save() = 0;
|
virtual void instant_save() = 0;
|
||||||
|
|
||||||
virtual void begin_selection_op_history () = 0;
|
virtual void begin_selection_op_history () = 0;
|
||||||
|
|
@ -172,9 +178,18 @@ class EditingContext : public ARDOUR::SessionHandlePtr, public AxisViewProvider
|
||||||
|
|
||||||
virtual void set_selected_midi_region_view (MidiRegionView&);
|
virtual void set_selected_midi_region_view (MidiRegionView&);
|
||||||
|
|
||||||
virtual void temporal_zoom_step (bool zoom_out) = 0;
|
|
||||||
samplecnt_t get_current_zoom () const { return samples_per_pixel; }
|
samplecnt_t get_current_zoom () const { return samples_per_pixel; }
|
||||||
|
|
||||||
|
void temporal_zoom_step (bool zoom_out);
|
||||||
|
void temporal_zoom_step_scale (bool zoom_out, double scale);
|
||||||
|
void temporal_zoom_step_mouse_focus (bool zoom_out);
|
||||||
|
void temporal_zoom_step_mouse_focus_scale (bool zoom_out, double scale);
|
||||||
|
|
||||||
|
void calc_extra_zoom_edges(samplepos_t &start, samplepos_t &end);
|
||||||
|
void temporal_zoom (samplecnt_t samples_per_pixel);
|
||||||
|
void temporal_zoom_by_sample (samplepos_t start, samplepos_t end);
|
||||||
|
void temporal_zoom_to_sample (bool coarser, samplepos_t sample);
|
||||||
|
|
||||||
double timeline_origin() const { return _timeline_origin; }
|
double timeline_origin() const { return _timeline_origin; }
|
||||||
|
|
||||||
/* NOTE: these functions assume that the "pixel" coordinate is
|
/* NOTE: these functions assume that the "pixel" coordinate is
|
||||||
|
|
@ -309,6 +324,8 @@ class EditingContext : public ARDOUR::SessionHandlePtr, public AxisViewProvider
|
||||||
|
|
||||||
virtual void set_zoom_focus (Editing::ZoomFocus) = 0;
|
virtual void set_zoom_focus (Editing::ZoomFocus) = 0;
|
||||||
virtual Editing::ZoomFocus get_zoom_focus () const = 0;
|
virtual Editing::ZoomFocus get_zoom_focus () const = 0;
|
||||||
|
void cycle_zoom_focus ();
|
||||||
|
|
||||||
virtual void reposition_and_zoom (samplepos_t, double) = 0;
|
virtual void reposition_and_zoom (samplepos_t, double) = 0;
|
||||||
|
|
||||||
sigc::signal<void> ZoomChanged;
|
sigc::signal<void> ZoomChanged;
|
||||||
|
|
@ -429,8 +446,18 @@ class EditingContext : public ARDOUR::SessionHandlePtr, public AxisViewProvider
|
||||||
|
|
||||||
virtual void set_canvas_cursor (Gdk::Cursor*);
|
virtual void set_canvas_cursor (Gdk::Cursor*);
|
||||||
|
|
||||||
|
/** computes the timeline sample (sample) of an event whose coordinates
|
||||||
|
* are in window units (pixels, no scroll offset).
|
||||||
|
*/
|
||||||
|
samplepos_t window_event_sample (GdkEvent const*, double* px = 0, double* py = 0) const;
|
||||||
|
|
||||||
|
/* returns false if mouse pointer is not in track or marker canvas
|
||||||
|
*/
|
||||||
|
bool mouse_sample (samplepos_t&, bool& in_track_canvas) const;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
std::string _name;
|
std::string _name;
|
||||||
|
bool within_track_canvas;
|
||||||
|
|
||||||
static Glib::RefPtr<Gtk::ActionGroup> _midi_actions;
|
static Glib::RefPtr<Gtk::ActionGroup> _midi_actions;
|
||||||
static Glib::RefPtr<Gtk::ActionGroup> _common_actions;
|
static Glib::RefPtr<Gtk::ActionGroup> _common_actions;
|
||||||
|
|
@ -531,6 +558,7 @@ class EditingContext : public ARDOUR::SessionHandlePtr, public AxisViewProvider
|
||||||
|
|
||||||
samplecnt_t samples_per_pixel;
|
samplecnt_t samples_per_pixel;
|
||||||
Editing::ZoomFocus zoom_focus;
|
Editing::ZoomFocus zoom_focus;
|
||||||
|
virtual Editing::ZoomFocus effective_zoom_focus() const { return zoom_focus; }
|
||||||
|
|
||||||
Temporal::timepos_t _snap_to_bbt (Temporal::timepos_t const & start,
|
Temporal::timepos_t _snap_to_bbt (Temporal::timepos_t const & start,
|
||||||
Temporal::RoundMode direction,
|
Temporal::RoundMode direction,
|
||||||
|
|
@ -699,6 +727,12 @@ class EditingContext : public ARDOUR::SessionHandlePtr, public AxisViewProvider
|
||||||
|
|
||||||
virtual void set_entered_track (TimeAxisView*) {};
|
virtual void set_entered_track (TimeAxisView*) {};
|
||||||
|
|
||||||
|
virtual std::pair<Temporal::timepos_t,Temporal::timepos_t> max_zoom_extent() const = 0;
|
||||||
|
|
||||||
|
virtual Temporal::timepos_t _get_preferred_edit_position (Editing::EditIgnoreOption,
|
||||||
|
bool use_context_click,
|
||||||
|
bool from_outside_canvas) = 0;
|
||||||
|
|
||||||
PBD::ScopedConnection escape_connection;
|
PBD::ScopedConnection escape_connection;
|
||||||
virtual void escape () {}
|
virtual void escape () {}
|
||||||
|
|
||||||
|
|
@ -719,5 +753,3 @@ class EditingContext : public ARDOUR::SessionHandlePtr, public AxisViewProvider
|
||||||
static EditingContext* _current_editing_context;
|
static EditingContext* _current_editing_context;
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -247,7 +247,6 @@ Editor::Editor ()
|
||||||
, _popup_region_menu_item (0)
|
, _popup_region_menu_item (0)
|
||||||
, _track_canvas (0)
|
, _track_canvas (0)
|
||||||
, _track_canvas_viewport (0)
|
, _track_canvas_viewport (0)
|
||||||
, within_track_canvas (false)
|
|
||||||
, _region_peak_cursor (0)
|
, _region_peak_cursor (0)
|
||||||
, tempo_group (0)
|
, tempo_group (0)
|
||||||
, meter_group (0)
|
, meter_group (0)
|
||||||
|
|
@ -3378,31 +3377,6 @@ Editor::set_zoom_focus (ZoomFocus f)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
|
||||||
Editor::cycle_zoom_focus ()
|
|
||||||
{
|
|
||||||
switch (zoom_focus) {
|
|
||||||
case ZoomFocusLeft:
|
|
||||||
set_zoom_focus (ZoomFocusRight);
|
|
||||||
break;
|
|
||||||
case ZoomFocusRight:
|
|
||||||
set_zoom_focus (ZoomFocusCenter);
|
|
||||||
break;
|
|
||||||
case ZoomFocusCenter:
|
|
||||||
set_zoom_focus (ZoomFocusPlayhead);
|
|
||||||
break;
|
|
||||||
case ZoomFocusPlayhead:
|
|
||||||
set_zoom_focus (ZoomFocusMouse);
|
|
||||||
break;
|
|
||||||
case ZoomFocusMouse:
|
|
||||||
set_zoom_focus (ZoomFocusEdit);
|
|
||||||
break;
|
|
||||||
case ZoomFocusEdit:
|
|
||||||
set_zoom_focus (ZoomFocusLeft);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
void
|
||||||
Editor::set_marker_click_behavior (MarkerClickBehavior m)
|
Editor::set_marker_click_behavior (MarkerClickBehavior m)
|
||||||
{
|
{
|
||||||
|
|
@ -4062,7 +4036,7 @@ Editor::sort_track_selection (TrackViewList& sel)
|
||||||
}
|
}
|
||||||
|
|
||||||
timepos_t
|
timepos_t
|
||||||
Editor::get_preferred_edit_position (EditIgnoreOption ignore, bool from_context_menu, bool from_outside_canvas)
|
Editor::_get_preferred_edit_position (EditIgnoreOption ignore, bool from_context_menu, bool from_outside_canvas)
|
||||||
{
|
{
|
||||||
bool ignored;
|
bool ignored;
|
||||||
timepos_t where;
|
timepos_t where;
|
||||||
|
|
|
||||||
|
|
@ -274,13 +274,6 @@ public:
|
||||||
|
|
||||||
bool process_midi_export_dialog (MidiExportDialog& dialog, std::shared_ptr<ARDOUR::MidiRegion> midi_region);
|
bool process_midi_export_dialog (MidiExportDialog& dialog, std::shared_ptr<ARDOUR::MidiRegion> midi_region);
|
||||||
|
|
||||||
void set_zoom_focus (Editing::ZoomFocus);
|
|
||||||
Editing::ZoomFocus get_zoom_focus () const { return zoom_focus; }
|
|
||||||
void cycle_zoom_focus ();
|
|
||||||
void temporal_zoom_step (bool zoom_out);
|
|
||||||
void temporal_zoom_step_scale (bool zoom_out, double scale);
|
|
||||||
void temporal_zoom_step_mouse_focus (bool zoom_out);
|
|
||||||
void temporal_zoom_step_mouse_focus_scale (bool zoom_out, double scale);
|
|
||||||
void ensure_time_axis_view_is_visible (TimeAxisView const & tav, bool at_top);
|
void ensure_time_axis_view_is_visible (TimeAxisView const & tav, bool at_top);
|
||||||
void tav_zoom_step (bool coarser);
|
void tav_zoom_step (bool coarser);
|
||||||
void tav_zoom_smooth (bool coarser, bool force_all);
|
void tav_zoom_smooth (bool coarser, bool force_all);
|
||||||
|
|
@ -377,10 +370,6 @@ public:
|
||||||
|
|
||||||
void reset_x_origin_to_follow_playhead ();
|
void reset_x_origin_to_follow_playhead ();
|
||||||
|
|
||||||
Temporal::timepos_t get_preferred_edit_position (Editing::EditIgnoreOption = Editing::EDIT_IGNORE_NONE,
|
|
||||||
bool use_context_click = false,
|
|
||||||
bool from_outside_canvas = false);
|
|
||||||
|
|
||||||
void toggle_meter_updating();
|
void toggle_meter_updating();
|
||||||
|
|
||||||
void show_rhythm_ferret();
|
void show_rhythm_ferret();
|
||||||
|
|
@ -514,6 +503,13 @@ public:
|
||||||
|
|
||||||
void focus_on_clock();
|
void focus_on_clock();
|
||||||
|
|
||||||
|
void set_zoom_focus (Editing::ZoomFocus);
|
||||||
|
Editing::ZoomFocus get_zoom_focus () const { return zoom_focus; }
|
||||||
|
|
||||||
|
void temporal_zoom_selection (Editing::ZoomAxis);
|
||||||
|
void temporal_zoom_session ();
|
||||||
|
void temporal_zoom_extents ();
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
void map_transport_state ();
|
void map_transport_state ();
|
||||||
void map_position_change (samplepos_t);
|
void map_position_change (samplepos_t);
|
||||||
|
|
@ -529,6 +525,8 @@ protected:
|
||||||
void do_undo (uint32_t n);
|
void do_undo (uint32_t n);
|
||||||
void do_redo (uint32_t n);
|
void do_redo (uint32_t n);
|
||||||
|
|
||||||
|
Temporal::timepos_t _get_preferred_edit_position (Editing::EditIgnoreOption, bool use_context_click, bool from_outside_canvas);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
void color_handler ();
|
void color_handler ();
|
||||||
|
|
@ -778,8 +776,6 @@ private:
|
||||||
ArdourCanvas::GtkCanvas* _track_canvas;
|
ArdourCanvas::GtkCanvas* _track_canvas;
|
||||||
ArdourCanvas::GtkCanvasViewport* _track_canvas_viewport;
|
ArdourCanvas::GtkCanvasViewport* _track_canvas_viewport;
|
||||||
|
|
||||||
bool within_track_canvas;
|
|
||||||
|
|
||||||
RegionPeakCursor* _region_peak_cursor;
|
RegionPeakCursor* _region_peak_cursor;
|
||||||
|
|
||||||
void parameter_changed (std::string);
|
void parameter_changed (std::string);
|
||||||
|
|
@ -1242,14 +1238,6 @@ private:
|
||||||
void group_selected_regions ();
|
void group_selected_regions ();
|
||||||
void ungroup_selected_regions ();
|
void ungroup_selected_regions ();
|
||||||
|
|
||||||
void calc_extra_zoom_edges(samplepos_t &start, samplepos_t &end);
|
|
||||||
void temporal_zoom_selection (Editing::ZoomAxis);
|
|
||||||
void temporal_zoom_session ();
|
|
||||||
void temporal_zoom_extents ();
|
|
||||||
void temporal_zoom (samplecnt_t samples_per_pixel);
|
|
||||||
void temporal_zoom_by_sample (samplepos_t start, samplepos_t end);
|
|
||||||
void temporal_zoom_to_sample (bool coarser, samplepos_t sample);
|
|
||||||
|
|
||||||
std::shared_ptr<ARDOUR::Playlist> current_playlist () const;
|
std::shared_ptr<ARDOUR::Playlist> current_playlist () const;
|
||||||
void insert_source_list_selection (float times);
|
void insert_source_list_selection (float times);
|
||||||
void cut_copy_section (ARDOUR::SectionOperation const op);
|
void cut_copy_section (ARDOUR::SectionOperation const op);
|
||||||
|
|
@ -1799,6 +1787,8 @@ private:
|
||||||
Gtk::HBox _box;
|
Gtk::HBox _box;
|
||||||
|
|
||||||
//zoom focus menu stuff
|
//zoom focus menu stuff
|
||||||
|
Editing::ZoomFocus effective_zoom_focus() const;
|
||||||
|
|
||||||
ArdourWidgets::ArdourDropdown zoom_focus_selector;
|
ArdourWidgets::ArdourDropdown zoom_focus_selector;
|
||||||
void zoom_focus_selection_done (Editing::ZoomFocus);
|
void zoom_focus_selection_done (Editing::ZoomFocus);
|
||||||
void build_zoom_focus_menu ();
|
void build_zoom_focus_menu ();
|
||||||
|
|
@ -1989,15 +1979,6 @@ private:
|
||||||
void duplicate_range (bool with_dialog);
|
void duplicate_range (bool with_dialog);
|
||||||
void duplicate_regions (float times);
|
void duplicate_regions (float times);
|
||||||
|
|
||||||
/** computes the timeline sample (sample) of an event whose coordinates
|
|
||||||
* are in window units (pixels, no scroll offset).
|
|
||||||
*/
|
|
||||||
samplepos_t window_event_sample (GdkEvent const*, double* px = 0, double* py = 0) const;
|
|
||||||
|
|
||||||
/* returns false if mouse pointer is not in track or marker canvas
|
|
||||||
*/
|
|
||||||
bool mouse_sample (samplepos_t&, bool& in_track_canvas) const;
|
|
||||||
|
|
||||||
TimeFXDialog* current_timefx;
|
TimeFXDialog* current_timefx;
|
||||||
static void* timefx_thread (void* arg);
|
static void* timefx_thread (void* arg);
|
||||||
void do_timefx (bool fixed_end);
|
void do_timefx (bool fixed_end);
|
||||||
|
|
@ -2062,6 +2043,8 @@ private:
|
||||||
void set_entered_regionview (RegionView*);
|
void set_entered_regionview (RegionView*);
|
||||||
gint left_automation_track ();
|
gint left_automation_track ();
|
||||||
|
|
||||||
|
std::pair<Temporal::timepos_t,Temporal::timepos_t> max_zoom_extent() const { return session_gui_extents(); }
|
||||||
|
|
||||||
void reset_canvas_action_sensitivity (bool);
|
void reset_canvas_action_sensitivity (bool);
|
||||||
void set_gain_envelope_visibility ();
|
void set_gain_envelope_visibility ();
|
||||||
void set_region_gain_visibility (RegionView*);
|
void set_region_gain_visibility (RegionView*);
|
||||||
|
|
|
||||||
|
|
@ -98,79 +98,6 @@ using namespace Temporal;
|
||||||
|
|
||||||
using Gtkmm2ext::Keyboard;
|
using Gtkmm2ext::Keyboard;
|
||||||
|
|
||||||
bool
|
|
||||||
Editor::mouse_sample (samplepos_t& where, bool& in_track_canvas) const
|
|
||||||
{
|
|
||||||
/* gdk_window_get_pointer() has X11's XQueryPointer semantics in that it only
|
|
||||||
* pays attentions to subwindows. this means that menu windows are ignored, and
|
|
||||||
* if the pointer is in a menu, the return window from the call will be the
|
|
||||||
* the regular subwindow *under* the menu.
|
|
||||||
*
|
|
||||||
* this matters quite a lot if the pointer is moving around in a menu that overlaps
|
|
||||||
* the track canvas because we will believe that we are within the track canvas
|
|
||||||
* when we are not. therefore, we track enter/leave events for the track canvas
|
|
||||||
* and allow that to override the result of gdk_window_get_pointer().
|
|
||||||
*/
|
|
||||||
|
|
||||||
if (!within_track_canvas) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
int x, y;
|
|
||||||
Glib::RefPtr<Gdk::Window> canvas_window = const_cast<Editor*>(this)->_track_canvas->get_window();
|
|
||||||
|
|
||||||
if (!canvas_window) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
Glib::RefPtr<const Gdk::Window> pointer_window = Gdk::Display::get_default()->get_window_at_pointer (x, y);
|
|
||||||
|
|
||||||
if (!pointer_window) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (pointer_window != canvas_window) {
|
|
||||||
in_track_canvas = false;
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
in_track_canvas = true;
|
|
||||||
|
|
||||||
GdkEvent event;
|
|
||||||
event.type = GDK_BUTTON_RELEASE;
|
|
||||||
event.button.x = x;
|
|
||||||
event.button.y = y;
|
|
||||||
|
|
||||||
where = window_event_sample (&event, 0, 0);
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
samplepos_t
|
|
||||||
Editor::window_event_sample (GdkEvent const * event, double* pcx, double* pcy) const
|
|
||||||
{
|
|
||||||
ArdourCanvas::Duple d;
|
|
||||||
|
|
||||||
if (!gdk_event_get_coords (event, &d.x, &d.y)) {
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* event coordinates are in window units, so convert to canvas
|
|
||||||
*/
|
|
||||||
|
|
||||||
d = _track_canvas->window_to_canvas (d);
|
|
||||||
|
|
||||||
if (pcx) {
|
|
||||||
*pcx = d.x;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (pcy) {
|
|
||||||
*pcy = d.y;
|
|
||||||
}
|
|
||||||
|
|
||||||
return pixel_to_sample (d.x);
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
void
|
||||||
Editor::set_current_trimmable (std::shared_ptr<Trimmable> t)
|
Editor::set_current_trimmable (std::shared_ptr<Trimmable> t)
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -1853,219 +1853,6 @@ Editor::tav_zoom_smooth (bool coarser, bool force_all)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
|
||||||
Editor::temporal_zoom_step_mouse_focus_scale (bool zoom_out, double scale)
|
|
||||||
{
|
|
||||||
PBD::Unwinder<Editing::ZoomFocus> zf (zoom_focus, Editing::ZoomFocusMouse);
|
|
||||||
temporal_zoom_step_scale (zoom_out, scale);
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
Editor::temporal_zoom_step_mouse_focus (bool zoom_out)
|
|
||||||
{
|
|
||||||
temporal_zoom_step_mouse_focus_scale (zoom_out, 2.0);
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
Editor::temporal_zoom_step (bool zoom_out)
|
|
||||||
{
|
|
||||||
temporal_zoom_step_scale (zoom_out, 2.0);
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
Editor::temporal_zoom_step_scale (bool zoom_out, double scale)
|
|
||||||
{
|
|
||||||
ENSURE_GUI_THREAD (*this, &Editor::temporal_zoom_step, zoom_out, scale)
|
|
||||||
|
|
||||||
samplecnt_t nspp = samples_per_pixel;
|
|
||||||
|
|
||||||
if (zoom_out) {
|
|
||||||
nspp *= scale;
|
|
||||||
if (nspp == samples_per_pixel) {
|
|
||||||
nspp *= 2.0;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
nspp /= scale;
|
|
||||||
if (nspp == samples_per_pixel) {
|
|
||||||
nspp /= 2.0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
//zoom-behavior-tweaks
|
|
||||||
//limit our maximum zoom to the session gui extents value
|
|
||||||
std::pair<timepos_t, timepos_t> ext = session_gui_extents();
|
|
||||||
samplecnt_t session_extents_pp = (ext.second.samples() - ext.first.samples()) / _visible_canvas_width;
|
|
||||||
if (nspp > session_extents_pp) {
|
|
||||||
nspp = session_extents_pp;
|
|
||||||
}
|
|
||||||
|
|
||||||
temporal_zoom (nspp);
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
Editor::temporal_zoom (samplecnt_t spp)
|
|
||||||
{
|
|
||||||
if (!_session) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
samplepos_t current_page = current_page_samples();
|
|
||||||
samplepos_t current_leftmost = _leftmost_sample;
|
|
||||||
samplepos_t current_rightmost;
|
|
||||||
samplepos_t current_center;
|
|
||||||
samplepos_t new_page_size;
|
|
||||||
samplepos_t half_page_size;
|
|
||||||
samplepos_t leftmost_after_zoom = 0;
|
|
||||||
samplepos_t where;
|
|
||||||
bool in_track_canvas;
|
|
||||||
bool use_mouse_sample = true;
|
|
||||||
samplecnt_t nspp;
|
|
||||||
double l;
|
|
||||||
|
|
||||||
if (spp == samples_per_pixel) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Imposing an arbitrary limit to zoom out as too much zoom out produces
|
|
||||||
// segfaults for lack of memory. If somebody decides this is not high enough I
|
|
||||||
// believe it can be raisen to higher values but some limit must be in place.
|
|
||||||
//
|
|
||||||
// This constant represents 1 day @ 48kHz on a 1600 pixel wide display
|
|
||||||
// all of which is used for the editor track displays. The whole day
|
|
||||||
// would be 4147200000 samples, so 2592000 samples per pixel.
|
|
||||||
|
|
||||||
nspp = min (spp, (samplecnt_t) 2592000);
|
|
||||||
nspp = max ((samplecnt_t) 1, nspp);
|
|
||||||
|
|
||||||
new_page_size = (samplepos_t) floor (_visible_canvas_width * nspp);
|
|
||||||
half_page_size = new_page_size / 2;
|
|
||||||
|
|
||||||
Editing::ZoomFocus zf = zoom_focus;
|
|
||||||
|
|
||||||
if (zf == ZoomFocusEdit && _edit_point == EditAtMouse) {
|
|
||||||
zf = ZoomFocusMouse;
|
|
||||||
}
|
|
||||||
|
|
||||||
switch (zf) {
|
|
||||||
case ZoomFocusLeft:
|
|
||||||
leftmost_after_zoom = current_leftmost;
|
|
||||||
break;
|
|
||||||
|
|
||||||
case ZoomFocusRight:
|
|
||||||
current_rightmost = _leftmost_sample + current_page;
|
|
||||||
if (current_rightmost < new_page_size) {
|
|
||||||
leftmost_after_zoom = 0;
|
|
||||||
} else {
|
|
||||||
leftmost_after_zoom = current_rightmost - new_page_size;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
|
|
||||||
case ZoomFocusCenter:
|
|
||||||
current_center = current_leftmost + (current_page/2);
|
|
||||||
if (current_center < half_page_size) {
|
|
||||||
leftmost_after_zoom = 0;
|
|
||||||
} else {
|
|
||||||
leftmost_after_zoom = current_center - half_page_size;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
|
|
||||||
case ZoomFocusPlayhead:
|
|
||||||
/* centre playhead */
|
|
||||||
l = _playhead_cursor->current_sample () - (new_page_size * 0.5);
|
|
||||||
|
|
||||||
if (l < 0) {
|
|
||||||
leftmost_after_zoom = 0;
|
|
||||||
} else if (l > max_samplepos) {
|
|
||||||
leftmost_after_zoom = max_samplepos - new_page_size;
|
|
||||||
} else {
|
|
||||||
leftmost_after_zoom = (samplepos_t) l;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
|
|
||||||
case ZoomFocusMouse:
|
|
||||||
/* try to keep the mouse over the same point in the display */
|
|
||||||
|
|
||||||
if (_drags->active()) {
|
|
||||||
where = _drags->current_pointer_sample ();
|
|
||||||
} else if (!mouse_sample (where, in_track_canvas)) {
|
|
||||||
use_mouse_sample = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (use_mouse_sample) {
|
|
||||||
l = - ((new_page_size * ((where - current_leftmost)/(double)current_page)) - where);
|
|
||||||
|
|
||||||
if (l < 0) {
|
|
||||||
leftmost_after_zoom = 0;
|
|
||||||
} else if (l > max_samplepos) {
|
|
||||||
leftmost_after_zoom = max_samplepos - new_page_size;
|
|
||||||
} else {
|
|
||||||
leftmost_after_zoom = (samplepos_t) l;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
/* use playhead instead */
|
|
||||||
where = _playhead_cursor->current_sample ();
|
|
||||||
|
|
||||||
if (where < half_page_size) {
|
|
||||||
leftmost_after_zoom = 0;
|
|
||||||
} else {
|
|
||||||
leftmost_after_zoom = where - half_page_size;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
|
|
||||||
case ZoomFocusEdit:
|
|
||||||
/* try to keep the edit point in the same place */
|
|
||||||
where = get_preferred_edit_position ().samples();
|
|
||||||
{
|
|
||||||
double l = - ((new_page_size * ((where - current_leftmost)/(double)current_page)) - where);
|
|
||||||
|
|
||||||
if (l < 0) {
|
|
||||||
leftmost_after_zoom = 0;
|
|
||||||
} else if (l > max_samplepos) {
|
|
||||||
leftmost_after_zoom = max_samplepos - new_page_size;
|
|
||||||
} else {
|
|
||||||
leftmost_after_zoom = (samplepos_t) l;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
// leftmost_after_zoom = min (leftmost_after_zoom, _session->current_end_sample());
|
|
||||||
|
|
||||||
reposition_and_zoom (leftmost_after_zoom, nspp);
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
Editor::calc_extra_zoom_edges(samplepos_t &start, samplepos_t &end)
|
|
||||||
{
|
|
||||||
/* this func helps make sure we leave a little space
|
|
||||||
at each end of the editor so that the zoom doesn't fit the region
|
|
||||||
precisely to the screen.
|
|
||||||
*/
|
|
||||||
|
|
||||||
GdkScreen* screen = gdk_screen_get_default ();
|
|
||||||
const gint pixwidth = gdk_screen_get_width (screen);
|
|
||||||
const gint mmwidth = gdk_screen_get_width_mm (screen);
|
|
||||||
const double pix_per_mm = (double) pixwidth/ (double) mmwidth;
|
|
||||||
const double one_centimeter_in_pixels = pix_per_mm * 10.0;
|
|
||||||
|
|
||||||
const samplepos_t range = end - start;
|
|
||||||
const samplecnt_t new_fpp = (samplecnt_t) ceil ((double) range / (double) _visible_canvas_width);
|
|
||||||
const samplepos_t extra_samples = (samplepos_t) floor (one_centimeter_in_pixels * new_fpp);
|
|
||||||
|
|
||||||
if (start > extra_samples) {
|
|
||||||
start -= extra_samples;
|
|
||||||
} else {
|
|
||||||
start = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (max_samplepos - extra_samples > end) {
|
|
||||||
end += extra_samples;
|
|
||||||
} else {
|
|
||||||
end = max_samplepos;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
bool
|
bool
|
||||||
Editor::get_selection_extents (timepos_t &start, timepos_t &end) const
|
Editor::get_selection_extents (timepos_t &start, timepos_t &end) const
|
||||||
|
|
@ -2107,205 +1894,6 @@ Editor::get_selection_extents (timepos_t &start, timepos_t &end) const
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void
|
|
||||||
Editor::temporal_zoom_selection (Editing::ZoomAxis axes)
|
|
||||||
{
|
|
||||||
if (!selection) return;
|
|
||||||
|
|
||||||
if (selection->regions.empty() && selection->time.empty()) {
|
|
||||||
if (axes == Horizontal || axes == Both) {
|
|
||||||
temporal_zoom_step(true);
|
|
||||||
}
|
|
||||||
if (axes == Vertical || axes == Both) {
|
|
||||||
if (!track_views.empty()) {
|
|
||||||
|
|
||||||
TrackViewList tvl;
|
|
||||||
|
|
||||||
//implicit hack: by extending the top & bottom check outside the current view limits, we include the trackviews immediately above & below what is visible
|
|
||||||
const double top = vertical_adjustment.get_value() - 10;
|
|
||||||
const double btm = top + _visible_canvas_height + 10;
|
|
||||||
|
|
||||||
for (TrackViewList::iterator iter = track_views.begin(); iter != track_views.end(); ++iter) {
|
|
||||||
if ((*iter)->covered_by_y_range (top, btm)) {
|
|
||||||
tvl.push_back(*iter);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fit_tracks (tvl);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
//ToDo: if notes are selected, zoom to that
|
|
||||||
|
|
||||||
//ToDo: if control points are selected, zoom to that
|
|
||||||
|
|
||||||
if (axes == Horizontal || axes == Both) {
|
|
||||||
|
|
||||||
timepos_t start, end;
|
|
||||||
if (get_selection_extents (start, end)) {
|
|
||||||
samplepos_t s = start.samples();
|
|
||||||
samplepos_t e = end.samples();
|
|
||||||
calc_extra_zoom_edges (s, e);
|
|
||||||
temporal_zoom_by_sample (s, e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (axes == Vertical || axes == Both) {
|
|
||||||
fit_selection ();
|
|
||||||
}
|
|
||||||
|
|
||||||
//normally, we don't do anything "automatic" to the user's selection.
|
|
||||||
//but in this case, we will clear the selection after a zoom-to-selection.
|
|
||||||
selection->clear();
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
Editor::temporal_zoom_session ()
|
|
||||||
{
|
|
||||||
ENSURE_GUI_THREAD (*this, &Editor::temporal_zoom_session)
|
|
||||||
|
|
||||||
if (_session) {
|
|
||||||
samplecnt_t start = _session->current_start_sample();
|
|
||||||
samplecnt_t end = _session->current_end_sample();
|
|
||||||
|
|
||||||
if (_session->actively_recording ()) {
|
|
||||||
samplepos_t cur = _playhead_cursor->current_sample ();
|
|
||||||
if (cur > end) {
|
|
||||||
/* recording beyond the end marker; zoom out
|
|
||||||
* by 5 seconds more so that if 'follow
|
|
||||||
* playhead' is active we don't immediately
|
|
||||||
* scroll.
|
|
||||||
*/
|
|
||||||
end = cur + _session->sample_rate() * 5;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if ((start == 0 && end == 0) || end < start) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
calc_extra_zoom_edges(start, end);
|
|
||||||
|
|
||||||
temporal_zoom_by_sample (start, end);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
Editor::temporal_zoom_extents ()
|
|
||||||
{
|
|
||||||
ENSURE_GUI_THREAD (*this, &Editor::temporal_zoom_extents)
|
|
||||||
|
|
||||||
if (_session) {
|
|
||||||
std::pair<timepos_t, timepos_t> ext = session_gui_extents (false); //in this case we want to zoom to the extents explicitly; ignore the users prefs for extra padding
|
|
||||||
|
|
||||||
samplecnt_t start = ext.first.samples();
|
|
||||||
samplecnt_t end = ext.second.samples();
|
|
||||||
|
|
||||||
if (_session->actively_recording ()) {
|
|
||||||
samplepos_t cur = _playhead_cursor->current_sample ();
|
|
||||||
if (cur > end) {
|
|
||||||
/* recording beyond the end marker; zoom out
|
|
||||||
* by 5 seconds more so that if 'follow
|
|
||||||
* playhead' is active we don't immediately
|
|
||||||
* scroll.
|
|
||||||
*/
|
|
||||||
end = cur + _session->sample_rate() * 5;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if ((start == 0 && end == 0) || end < start) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
calc_extra_zoom_edges(start, end);
|
|
||||||
|
|
||||||
temporal_zoom_by_sample (start, end);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
Editor::temporal_zoom_by_sample (samplepos_t start, samplepos_t end)
|
|
||||||
{
|
|
||||||
if (!_session) return;
|
|
||||||
|
|
||||||
if ((start == 0 && end == 0) || end < start) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
samplepos_t range = end - start;
|
|
||||||
|
|
||||||
const samplecnt_t new_fpp = (samplecnt_t) ceil ((double) range / (double) _visible_canvas_width);
|
|
||||||
|
|
||||||
samplepos_t new_page = range;
|
|
||||||
samplepos_t middle = (samplepos_t) floor ((double) start + ((double) range / 2.0f));
|
|
||||||
samplepos_t new_leftmost = (samplepos_t) floor ((double) middle - ((double) new_page / 2.0f));
|
|
||||||
|
|
||||||
if (new_leftmost > middle) {
|
|
||||||
new_leftmost = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (new_leftmost < 0) {
|
|
||||||
new_leftmost = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
reposition_and_zoom (new_leftmost, new_fpp);
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
Editor::temporal_zoom_to_sample (bool coarser, samplepos_t sample)
|
|
||||||
{
|
|
||||||
if (!_session) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
samplecnt_t range_before = sample - _leftmost_sample;
|
|
||||||
samplecnt_t new_spp;
|
|
||||||
|
|
||||||
if (coarser) {
|
|
||||||
if (samples_per_pixel <= 1) {
|
|
||||||
new_spp = 2;
|
|
||||||
} else {
|
|
||||||
new_spp = samples_per_pixel + (samples_per_pixel/2);
|
|
||||||
}
|
|
||||||
range_before += range_before/2;
|
|
||||||
} else {
|
|
||||||
if (samples_per_pixel >= 1) {
|
|
||||||
new_spp = samples_per_pixel - (samples_per_pixel/2);
|
|
||||||
} else {
|
|
||||||
/* could bail out here since we cannot zoom any finer,
|
|
||||||
but leave that to the equality test below
|
|
||||||
*/
|
|
||||||
new_spp = samples_per_pixel;
|
|
||||||
}
|
|
||||||
|
|
||||||
range_before -= range_before/2;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (new_spp == samples_per_pixel) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* zoom focus is automatically taken as @p sample when this
|
|
||||||
method is used.
|
|
||||||
*/
|
|
||||||
|
|
||||||
samplepos_t new_leftmost = sample - (samplepos_t)range_before;
|
|
||||||
|
|
||||||
if (new_leftmost > sample) {
|
|
||||||
new_leftmost = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (new_leftmost < 0) {
|
|
||||||
new_leftmost = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
reposition_and_zoom (new_leftmost, new_spp);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
bool
|
bool
|
||||||
Editor::choose_new_marker_name(string &name, bool is_range) {
|
Editor::choose_new_marker_name(string &name, bool is_range) {
|
||||||
|
|
||||||
|
|
@ -9804,3 +9392,131 @@ Editor::ripple_marks (std::shared_ptr<Playlist> target_playlist, timepos_t at, t
|
||||||
_session->locations()->ripple (at, distance, false);
|
_session->locations()->ripple (at, distance, false);
|
||||||
_session->add_command (new MementoCommand<Locations> (*_session->locations(), &before, &_session->locations()->get_state()));
|
_session->add_command (new MementoCommand<Locations> (*_session->locations(), &before, &_session->locations()->get_state()));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Editing::ZoomFocus
|
||||||
|
Editor::effective_zoom_focus() const
|
||||||
|
{
|
||||||
|
if (zoom_focus == ZoomFocusEdit && _edit_point == EditAtMouse) {
|
||||||
|
return ZoomFocusMouse;
|
||||||
|
}
|
||||||
|
|
||||||
|
return zoom_focus;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
Editor::temporal_zoom_selection (Editing::ZoomAxis axes)
|
||||||
|
{
|
||||||
|
if (!selection) return;
|
||||||
|
|
||||||
|
if (selection->regions.empty() && selection->time.empty()) {
|
||||||
|
if (axes == Horizontal || axes == Both) {
|
||||||
|
temporal_zoom_step(true);
|
||||||
|
}
|
||||||
|
if (axes == Vertical || axes == Both) {
|
||||||
|
if (!track_views.empty()) {
|
||||||
|
|
||||||
|
TrackViewList tvl;
|
||||||
|
|
||||||
|
//implicit hack: by extending the top & bottom check outside the current view limits, we include the trackviews immediately above & below what is visible
|
||||||
|
const double top = vertical_adjustment.get_value() - 10;
|
||||||
|
const double btm = top + _visible_canvas_height + 10;
|
||||||
|
|
||||||
|
for (TrackViewList::iterator iter = track_views.begin(); iter != track_views.end(); ++iter) {
|
||||||
|
if ((*iter)->covered_by_y_range (top, btm)) {
|
||||||
|
tvl.push_back(*iter);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fit_tracks (tvl);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
//ToDo: if notes are selected, zoom to that
|
||||||
|
|
||||||
|
//ToDo: if control points are selected, zoom to that
|
||||||
|
|
||||||
|
if (axes == Horizontal || axes == Both) {
|
||||||
|
|
||||||
|
timepos_t start, end;
|
||||||
|
if (get_selection_extents (start, end)) {
|
||||||
|
samplepos_t s = start.samples();
|
||||||
|
samplepos_t e = end.samples();
|
||||||
|
calc_extra_zoom_edges (s, e);
|
||||||
|
temporal_zoom_by_sample (s, e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (axes == Vertical || axes == Both) {
|
||||||
|
fit_selection ();
|
||||||
|
}
|
||||||
|
|
||||||
|
//normally, we don't do anything "automatic" to the user's selection.
|
||||||
|
//but in this case, we will clear the selection after a zoom-to-selection.
|
||||||
|
selection->clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
Editor::temporal_zoom_session ()
|
||||||
|
{
|
||||||
|
ENSURE_GUI_THREAD (*this, &Editor::temporal_zoom_session)
|
||||||
|
|
||||||
|
if (_session) {
|
||||||
|
samplecnt_t start = _session->current_start_sample();
|
||||||
|
samplecnt_t end = _session->current_end_sample();
|
||||||
|
|
||||||
|
if (_session->actively_recording ()) {
|
||||||
|
samplepos_t cur = _playhead_cursor->current_sample ();
|
||||||
|
if (cur > end) {
|
||||||
|
/* recording beyond the end marker; zoom out
|
||||||
|
* by 5 seconds more so that if 'follow
|
||||||
|
* playhead' is active we don't immediately
|
||||||
|
* scroll.
|
||||||
|
*/
|
||||||
|
end = cur + _session->sample_rate() * 5;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((start == 0 && end == 0) || end < start) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
calc_extra_zoom_edges(start, end);
|
||||||
|
|
||||||
|
temporal_zoom_by_sample (start, end);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
Editor::temporal_zoom_extents ()
|
||||||
|
{
|
||||||
|
ENSURE_GUI_THREAD (*this, &Editor::temporal_zoom_extents)
|
||||||
|
|
||||||
|
if (_session) {
|
||||||
|
std::pair<timepos_t, timepos_t> ext = session_gui_extents (false); //in this case we want to zoom to the extents explicitly; ignore the users prefs for extra padding
|
||||||
|
|
||||||
|
samplecnt_t start = ext.first.samples();
|
||||||
|
samplecnt_t end = ext.second.samples();
|
||||||
|
|
||||||
|
if (_session->actively_recording ()) {
|
||||||
|
samplepos_t cur = _playhead_cursor->current_sample ();
|
||||||
|
if (cur > end) {
|
||||||
|
/* recording beyond the end marker; zoom out
|
||||||
|
* by 5 seconds more so that if 'follow
|
||||||
|
* playhead' is active we don't immediately
|
||||||
|
* scroll.
|
||||||
|
*/
|
||||||
|
end = cur + _session->sample_rate() * 5;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((start == 0 && end == 0) || end < start) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
calc_extra_zoom_edges(start, end);
|
||||||
|
|
||||||
|
temporal_zoom_by_sample (start, end);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -290,7 +290,6 @@ public:
|
||||||
virtual samplepos_t leftmost_sample() const = 0;
|
virtual samplepos_t leftmost_sample() const = 0;
|
||||||
virtual samplecnt_t current_page_samples() const = 0;
|
virtual samplecnt_t current_page_samples() const = 0;
|
||||||
virtual double visible_canvas_height () const = 0;
|
virtual double visible_canvas_height () const = 0;
|
||||||
virtual void temporal_zoom_step (bool coarser) = 0;
|
|
||||||
virtual void ensure_time_axis_view_is_visible (TimeAxisView const & tav, bool at_top = false) = 0;
|
virtual void ensure_time_axis_view_is_visible (TimeAxisView const & tav, bool at_top = false) = 0;
|
||||||
virtual void override_visible_track_count () = 0;
|
virtual void override_visible_track_count () = 0;
|
||||||
virtual void scroll_tracks_down_line () = 0;
|
virtual void scroll_tracks_down_line () = 0;
|
||||||
|
|
@ -306,7 +305,6 @@ public:
|
||||||
virtual void remove_last_capture () = 0;
|
virtual void remove_last_capture () = 0;
|
||||||
virtual void maximise_editing_space () = 0;
|
virtual void maximise_editing_space () = 0;
|
||||||
virtual void restore_editing_space () = 0;
|
virtual void restore_editing_space () = 0;
|
||||||
virtual Temporal::timepos_t get_preferred_edit_position (Editing::EditIgnoreOption = Editing::EDIT_IGNORE_NONE, bool from_context_menu = false, bool from_outside_canvas = false) = 0;
|
|
||||||
virtual void toggle_meter_updating() = 0;
|
virtual void toggle_meter_updating() = 0;
|
||||||
virtual void split_regions_at (Temporal::timepos_t const &, RegionSelection&) = 0;
|
virtual void split_regions_at (Temporal::timepos_t const &, RegionSelection&) = 0;
|
||||||
virtual void split_region_at_points (std::shared_ptr<ARDOUR::Region>, ARDOUR::AnalysisFeatureList&, bool can_ferret, bool select_new = false) = 0;
|
virtual void split_region_at_points (std::shared_ptr<ARDOUR::Region>, ARDOUR::AnalysisFeatureList&, bool can_ferret, bool select_new = false) = 0;
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue