WaveTrack does not depend directly on ProjectHistory...

... because  we undo the move,
"Demote vertical zooming code into WaveTrack.cpp ..." done at 1f4bf26

That was done so that WaveTrack would not depend on WaveTrackVZoomHandle, but
made it instead depend on ProjectHistory, which is undesirable.

But since then, commit 3797a52 moved the special minimizing code for WaveTrack
into WaveTrackView.
This commit is contained in:
Paul Licameli 2019-06-11 02:29:56 -04:00
parent 499e3c01ce
commit aa1ce03100
6 changed files with 314 additions and 317 deletions

View File

@ -2829,299 +2829,3 @@ void WaveTrack::AllClipsIterator::push( WaveClipHolders &clips )
pClips = &(*first)->GetCutLines();
}
}
void WaveTrack::DoZoomPreset( int i)
{
// Don't do all channels, that causes problems when updating display
// during recording and there are special pending tracks.
// This function implements WaveTrack::DoSetMinimized which is always
// called in a context that loops over linked tracks too and reinvokes.
WaveTrack::DoZoom(
NULL, this, false, (i==1)?kZoomHalfWave: kZoom1to1,
wxRect(0,0,0,0), 0,0, true);
}
#include "NumberScale.h"
#include "ProjectHistory.h"
static bool IsDragZooming(int zoomStart, int zoomEnd)
{
const int DragThreshold = 3;// Anything over 3 pixels is a drag, else a click.
bool bVZoom;
gPrefs->Read(wxT("/GUI/VerticalZooming"), &bVZoom, false);
return bVZoom && (abs(zoomEnd - zoomStart) > DragThreshold);
}
// ZoomKind says how to zoom.
// If ZoomStart and ZoomEnd are not equal, this may override
// the zoomKind and cause a drag-zoom-in.
void WaveTrack::DoZoom
(AudacityProject *pProject,
WaveTrack *pTrack, bool allChannels, int ZoomKind,
const wxRect &rect, int zoomStart, int zoomEnd,
bool fixedMousePoint)
{
static const float ZOOMLIMIT = 0.001f;
int height = rect.height;
int ypos = rect.y;
// Ensure start and end are in order (swap if not).
if (zoomEnd < zoomStart)
std::swap( zoomStart, zoomEnd );
float min, max, minBand = 0;
const double rate = pTrack->GetRate();
const float halfrate = rate / 2;
float maxFreq = 8000.0;
const SpectrogramSettings &specSettings = pTrack->GetSpectrogramSettings();
NumberScale scale;
const bool spectral = (pTrack->GetDisplay() == WaveTrack::Spectrum);
const bool spectrumLinear = spectral &&
(pTrack->GetSpectrogramSettings().scaleType == SpectrogramSettings::stLinear);
bool bDragZoom = IsDragZooming(zoomStart, zoomEnd);
// Add 100 if spectral to separate the kinds of zoom.
const int kSpectral = 100;
// Possibly override the zoom kind.
if( bDragZoom )
ZoomKind = kZoomInByDrag;
// If we are actually zooming a spectrum rather than a wave.
ZoomKind += spectral ? kSpectral:0;
float top=2.0;
float half=0.5;
if (spectral) {
pTrack->GetSpectrumBounds(&min, &max);
scale = (specSettings.GetScale(min, max));
const auto fftLength = specSettings.GetFFTLength();
const float binSize = rate / fftLength;
maxFreq = gPrefs->Read(wxT("/Spectrum/MaxFreq"), 8000L);
// JKC: Following discussions of Bug 1208 I'm allowing zooming in
// down to one bin.
// const int minBins =
// std::min(10, fftLength / 2); //minimum 10 freq bins, unless there are less
const int minBins = 1;
minBand = minBins * binSize;
}
else{
pTrack->GetDisplayBounds(&min, &max);
const WaveformSettings &waveSettings = pTrack->GetWaveformSettings();
const bool linear = waveSettings.isLinear();
if( !linear ){
top = (LINEAR_TO_DB(2.0) + waveSettings.dBRange) / waveSettings.dBRange;
half = (LINEAR_TO_DB(0.5) + waveSettings.dBRange) / waveSettings.dBRange;
}
}
// Compute min and max.
switch(ZoomKind)
{
default:
// If we have covered all the cases, this won't happen.
// In release builds Audacity will ignore the zoom.
wxFAIL_MSG("Zooming Case not implemented by Audacity");
break;
case kZoomReset:
case kZoom1to1:
{
// Zoom out full
min = -1.0;
max = 1.0;
}
break;
case kZoomDiv2:
{
// Zoom out even more than full :-)
// -2.0..+2.0 (or logarithmic equivalent)
min = -top;
max = top;
}
break;
case kZoomTimes2:
{
// Zoom in to -0.5..+0.5
min = -half;
max = half;
}
break;
case kZoomHalfWave:
{
// Zoom to show fractionally more than the top half of the wave.
min = -0.01f;
max = 1.0;
}
break;
case kZoomInByDrag:
{
const float tmin = min, tmax = max;
const float p1 = (zoomStart - ypos) / (float)height;
const float p2 = (zoomEnd - ypos) / (float)height;
max = (tmax * (1.0 - p1) + tmin * p1);
min = (tmax * (1.0 - p2) + tmin * p2);
// Waveform view - allow zooming down to a range of ZOOMLIMIT
if (max - min < ZOOMLIMIT) { // if user attempts to go smaller...
float c = (min + max) / 2; // ...set centre of view to centre of dragged area and top/bottom to ZOOMLIMIT/2 above/below
min = c - ZOOMLIMIT / 2.0;
max = c + ZOOMLIMIT / 2.0;
}
}
break;
case kZoomIn:
{
// Enforce maximum vertical zoom
const float oldRange = max - min;
const float l = std::max(ZOOMLIMIT, 0.5f * oldRange);
const float ratio = l / (max - min);
const float p1 = (zoomStart - ypos) / (float)height;
float c = (max * (1.0 - p1) + min * p1);
if (fixedMousePoint)
min = c - ratio * (1.0f - p1) * oldRange,
max = c + ratio * p1 * oldRange;
else
min = c - 0.5 * l,
max = c + 0.5 * l;
}
break;
case kZoomOut:
{
// Zoom out
if (min <= -1.0 && max >= 1.0) {
min = -top;
max = top;
}
else {
// limit to +/- 1 range unless already outside that range...
float minRange = (min < -1) ? -top : -1.0;
float maxRange = (max > 1) ? top : 1.0;
// and enforce vertical zoom limits.
const float p1 = (zoomStart - ypos) / (float)height;
if (fixedMousePoint) {
const float oldRange = max - min;
const float c = (max * (1.0 - p1) + min * p1);
min = std::min(maxRange - ZOOMLIMIT,
std::max(minRange, c - 2 * (1.0f - p1) * oldRange));
max = std::max(minRange + ZOOMLIMIT,
std::min(maxRange, c + 2 * p1 * oldRange));
}
else {
const float c = p1 * min + (1 - p1) * max;
const float l = (max - min);
min = std::min(maxRange - ZOOMLIMIT,
std::max(minRange, c - l));
max = std::max(minRange + ZOOMLIMIT,
std::min(maxRange, c + l));
}
}
}
break;
// VZooming on spectral we don't implement the other zoom presets.
// They are also not in the menu.
case kZoomReset + kSpectral:
{
// Zoom out to normal level.
min = spectrumLinear ? 0.0f : 1.0f;
max = maxFreq;
}
break;
case kZoom1to1 + kSpectral:
case kZoomDiv2 + kSpectral:
case kZoomTimes2 + kSpectral:
case kZoomHalfWave + kSpectral:
{
// Zoom out full
min = spectrumLinear ? 0.0f : 1.0f;
max = halfrate;
}
break;
case kZoomInByDrag + kSpectral:
{
double xmin = 1 - (zoomEnd - ypos) / (float)height;
double xmax = 1 - (zoomStart - ypos) / (float)height;
const float middle = (xmin + xmax) / 2;
const float middleValue = scale.PositionToValue(middle);
min = std::max(spectrumLinear ? 0.0f : 1.0f,
std::min(middleValue - minBand / 2,
scale.PositionToValue(xmin)
));
max = std::min(halfrate,
std::max(middleValue + minBand / 2,
scale.PositionToValue(xmax)
));
}
break;
case kZoomIn + kSpectral:
{
// Center the zoom-in at the click
const float p1 = (zoomStart - ypos) / (float)height;
const float middle = 1.0f - p1;
const float middleValue = scale.PositionToValue(middle);
if (fixedMousePoint) {
min = std::max(spectrumLinear ? 0.0f : 1.0f,
std::min(middleValue - minBand * middle,
scale.PositionToValue(0.5f * middle)
));
max = std::min(halfrate,
std::max(middleValue + minBand * p1,
scale.PositionToValue(middle + 0.5f * p1)
));
}
else {
min = std::max(spectrumLinear ? 0.0f : 1.0f,
std::min(middleValue - minBand / 2,
scale.PositionToValue(middle - 0.25f)
));
max = std::min(halfrate,
std::max(middleValue + minBand / 2,
scale.PositionToValue(middle + 0.25f)
));
}
}
break;
case kZoomOut + kSpectral:
{
// Zoom out
const float p1 = (zoomStart - ypos) / (float)height;
// (Used to zoom out centered at midline, ignoring the click, if linear view.
// I think it is better to be consistent. PRL)
// Center zoom-out at the midline
const float middle = // spectrumLinear ? 0.5f :
1.0f - p1;
if (fixedMousePoint) {
min = std::max(spectrumLinear ? 0.0f : 1.0f, scale.PositionToValue(-middle));
max = std::min(halfrate, scale.PositionToValue(1.0f + p1));
}
else {
min = std::max(spectrumLinear ? 0.0f : 1.0f, scale.PositionToValue(middle - 1.0f));
max = std::min(halfrate, scale.PositionToValue(middle + 1.0f));
}
}
break;
}
// Now actually apply the zoom.
for (auto channel : TrackList::Channels(pTrack)) {
if (!allChannels && channel != pTrack)
continue;
if (spectral)
channel->SetSpectrumBounds(min, max);
else
channel->SetDisplayBounds(min, max);
}
zoomEnd = zoomStart = 0;
if( pProject )
ProjectHistory::Get( *pProject ).ModifyState(true);
}

View File

@ -61,17 +61,6 @@ using Regions = std::vector < Region >;
class Envelope;
// Note that these can be with or without spectrum view which
// adds a constant.
const int kZoom1to1 = 1;
const int kZoomTimes2 = 2;
const int kZoomDiv2 = 3;
const int kZoomHalfWave = 4;
const int kZoomInByDrag = 5;
const int kZoomIn = 6;
const int kZoomOut = 7;
const int kZoomReset = 8;
class AUDACITY_DLL_API WaveTrack final : public PlayableTrack {
public:
@ -552,13 +541,6 @@ private:
//
static void DoZoom
(AudacityProject *pProject,
WaveTrack *pTrack, bool allChannels, int ZoomKind,
const wxRect &rect, int zoomStart, int zoomEnd,
bool fixedMousePoint);
void DoZoomPreset( int i);
typedef int WaveTrackDisplay;
enum WaveTrackDisplayValues : int {

View File

@ -49,6 +49,25 @@ std::vector<UIHandlePtr> WaveTrackVRulerControls::HitTest
return results;
}
void WaveTrackVRulerControls::DoZoomPreset( int i)
{
const auto pTrack = FindTrack();
if (!pTrack)
return;
const auto wt = static_cast<WaveTrack*>(pTrack.get());
// Don't do all channels, that causes problems when updating display
// during recording and there are special pending tracks.
// This function implements WaveTrack::DoSetMinimized which is always
// called in a context that loops over linked tracks too and reinvokes.
WaveTrackVZoomHandle::DoZoom(
NULL, wt, false, (i==1)?kZoomHalfWave: kZoom1to1,
wxRect(0,0,0,0), 0,0, true);
}
unsigned WaveTrackVRulerControls::HandleWheelRotation
(const TrackPanelMouseEvent &evt, AudacityProject *pProject)
{
@ -116,7 +135,7 @@ unsigned WaveTrackVRulerControls::HandleWheelRotation
}
else if (event.CmdDown() && !event.ShiftDown()) {
const int yy = event.m_y;
WaveTrack::DoZoom(
WaveTrackVZoomHandle::DoZoom(
pProject, wt, true, (steps < 0)?kZoomOut:kZoomIn,
evt.rect, yy, yy, true);
}

View File

@ -33,6 +33,7 @@ public:
unsigned HandleWheelRotation
(const TrackPanelMouseEvent &event,
AudacityProject *pProject) override;
void DoZoomPreset( int i);
private:
std::weak_ptr<WaveTrackVZoomHandle> mVZoomHandle;
};

View File

@ -16,6 +16,7 @@ Paul Licameli split from TrackPanel.cpp
#include "WaveTrackVRulerControls.h"
#include "../../../../HitTestResult.h"
#include "../../../../NumberScale.h"
#include "../../../../prefs/SpectrogramSettings.h"
#include "../../../../prefs/WaveformSettings.h"
#include "../../../../Project.h"
@ -62,6 +63,279 @@ void WaveTrackVZoomHandle::Enter(bool)
#endif
}
// ZoomKind says how to zoom.
// If ZoomStart and ZoomEnd are not equal, this may override
// the zoomKind and cause a drag-zoom-in.
void WaveTrackVZoomHandle::DoZoom
(AudacityProject *pProject,
WaveTrack *pTrack, bool allChannels, int ZoomKind,
const wxRect &rect, int zoomStart, int zoomEnd,
bool fixedMousePoint)
{
static const float ZOOMLIMIT = 0.001f;
int height = rect.height;
int ypos = rect.y;
// Ensure start and end are in order (swap if not).
if (zoomEnd < zoomStart)
std::swap( zoomStart, zoomEnd );
float min, max, minBand = 0;
const double rate = pTrack->GetRate();
const float halfrate = rate / 2;
float maxFreq = 8000.0;
const SpectrogramSettings &specSettings = pTrack->GetSpectrogramSettings();
NumberScale scale;
const bool spectral = (pTrack->GetDisplay() == WaveTrack::Spectrum);
const bool spectrumLinear = spectral &&
(pTrack->GetSpectrogramSettings().scaleType == SpectrogramSettings::stLinear);
bool bDragZoom = IsDragZooming(zoomStart, zoomEnd);
// Add 100 if spectral to separate the kinds of zoom.
const int kSpectral = 100;
// Possibly override the zoom kind.
if( bDragZoom )
ZoomKind = kZoomInByDrag;
// If we are actually zooming a spectrum rather than a wave.
ZoomKind += spectral ? kSpectral:0;
float top=2.0;
float half=0.5;
if (spectral) {
pTrack->GetSpectrumBounds(&min, &max);
scale = (specSettings.GetScale(min, max));
const auto fftLength = specSettings.GetFFTLength();
const float binSize = rate / fftLength;
maxFreq = gPrefs->Read(wxT("/Spectrum/MaxFreq"), 8000L);
// JKC: Following discussions of Bug 1208 I'm allowing zooming in
// down to one bin.
// const int minBins =
// std::min(10, fftLength / 2); //minimum 10 freq bins, unless there are less
const int minBins = 1;
minBand = minBins * binSize;
}
else{
pTrack->GetDisplayBounds(&min, &max);
const WaveformSettings &waveSettings = pTrack->GetWaveformSettings();
const bool linear = waveSettings.isLinear();
if( !linear ){
top = (LINEAR_TO_DB(2.0) + waveSettings.dBRange) / waveSettings.dBRange;
half = (LINEAR_TO_DB(0.5) + waveSettings.dBRange) / waveSettings.dBRange;
}
}
// Compute min and max.
switch(ZoomKind)
{
default:
// If we have covered all the cases, this won't happen.
// In release builds Audacity will ignore the zoom.
wxFAIL_MSG("Zooming Case not implemented by Audacity");
break;
case kZoomReset:
case kZoom1to1:
{
// Zoom out full
min = -1.0;
max = 1.0;
}
break;
case kZoomDiv2:
{
// Zoom out even more than full :-)
// -2.0..+2.0 (or logarithmic equivalent)
min = -top;
max = top;
}
break;
case kZoomTimes2:
{
// Zoom in to -0.5..+0.5
min = -half;
max = half;
}
break;
case kZoomHalfWave:
{
// Zoom to show fractionally more than the top half of the wave.
min = -0.01f;
max = 1.0;
}
break;
case kZoomInByDrag:
{
const float tmin = min, tmax = max;
const float p1 = (zoomStart - ypos) / (float)height;
const float p2 = (zoomEnd - ypos) / (float)height;
max = (tmax * (1.0 - p1) + tmin * p1);
min = (tmax * (1.0 - p2) + tmin * p2);
// Waveform view - allow zooming down to a range of ZOOMLIMIT
if (max - min < ZOOMLIMIT) { // if user attempts to go smaller...
float c = (min + max) / 2; // ...set centre of view to centre of dragged area and top/bottom to ZOOMLIMIT/2 above/below
min = c - ZOOMLIMIT / 2.0;
max = c + ZOOMLIMIT / 2.0;
}
}
break;
case kZoomIn:
{
// Enforce maximum vertical zoom
const float oldRange = max - min;
const float l = std::max(ZOOMLIMIT, 0.5f * oldRange);
const float ratio = l / (max - min);
const float p1 = (zoomStart - ypos) / (float)height;
float c = (max * (1.0 - p1) + min * p1);
if (fixedMousePoint)
min = c - ratio * (1.0f - p1) * oldRange,
max = c + ratio * p1 * oldRange;
else
min = c - 0.5 * l,
max = c + 0.5 * l;
}
break;
case kZoomOut:
{
// Zoom out
if (min <= -1.0 && max >= 1.0) {
min = -top;
max = top;
}
else {
// limit to +/- 1 range unless already outside that range...
float minRange = (min < -1) ? -top : -1.0;
float maxRange = (max > 1) ? top : 1.0;
// and enforce vertical zoom limits.
const float p1 = (zoomStart - ypos) / (float)height;
if (fixedMousePoint) {
const float oldRange = max - min;
const float c = (max * (1.0 - p1) + min * p1);
min = std::min(maxRange - ZOOMLIMIT,
std::max(minRange, c - 2 * (1.0f - p1) * oldRange));
max = std::max(minRange + ZOOMLIMIT,
std::min(maxRange, c + 2 * p1 * oldRange));
}
else {
const float c = p1 * min + (1 - p1) * max;
const float l = (max - min);
min = std::min(maxRange - ZOOMLIMIT,
std::max(minRange, c - l));
max = std::max(minRange + ZOOMLIMIT,
std::min(maxRange, c + l));
}
}
}
break;
// VZooming on spectral we don't implement the other zoom presets.
// They are also not in the menu.
case kZoomReset + kSpectral:
{
// Zoom out to normal level.
min = spectrumLinear ? 0.0f : 1.0f;
max = maxFreq;
}
break;
case kZoom1to1 + kSpectral:
case kZoomDiv2 + kSpectral:
case kZoomTimes2 + kSpectral:
case kZoomHalfWave + kSpectral:
{
// Zoom out full
min = spectrumLinear ? 0.0f : 1.0f;
max = halfrate;
}
break;
case kZoomInByDrag + kSpectral:
{
double xmin = 1 - (zoomEnd - ypos) / (float)height;
double xmax = 1 - (zoomStart - ypos) / (float)height;
const float middle = (xmin + xmax) / 2;
const float middleValue = scale.PositionToValue(middle);
min = std::max(spectrumLinear ? 0.0f : 1.0f,
std::min(middleValue - minBand / 2,
scale.PositionToValue(xmin)
));
max = std::min(halfrate,
std::max(middleValue + minBand / 2,
scale.PositionToValue(xmax)
));
}
break;
case kZoomIn + kSpectral:
{
// Center the zoom-in at the click
const float p1 = (zoomStart - ypos) / (float)height;
const float middle = 1.0f - p1;
const float middleValue = scale.PositionToValue(middle);
if (fixedMousePoint) {
min = std::max(spectrumLinear ? 0.0f : 1.0f,
std::min(middleValue - minBand * middle,
scale.PositionToValue(0.5f * middle)
));
max = std::min(halfrate,
std::max(middleValue + minBand * p1,
scale.PositionToValue(middle + 0.5f * p1)
));
}
else {
min = std::max(spectrumLinear ? 0.0f : 1.0f,
std::min(middleValue - minBand / 2,
scale.PositionToValue(middle - 0.25f)
));
max = std::min(halfrate,
std::max(middleValue + minBand / 2,
scale.PositionToValue(middle + 0.25f)
));
}
}
break;
case kZoomOut + kSpectral:
{
// Zoom out
const float p1 = (zoomStart - ypos) / (float)height;
// (Used to zoom out centered at midline, ignoring the click, if linear view.
// I think it is better to be consistent. PRL)
// Center zoom-out at the midline
const float middle = // spectrumLinear ? 0.5f :
1.0f - p1;
if (fixedMousePoint) {
min = std::max(spectrumLinear ? 0.0f : 1.0f, scale.PositionToValue(-middle));
max = std::min(halfrate, scale.PositionToValue(1.0f + p1));
}
else {
min = std::max(spectrumLinear ? 0.0f : 1.0f, scale.PositionToValue(middle - 1.0f));
max = std::min(halfrate, scale.PositionToValue(middle + 1.0f));
}
}
break;
}
// Now actually apply the zoom.
for (auto channel : TrackList::Channels(pTrack)) {
if (!allChannels && channel != pTrack)
continue;
if (spectral)
channel->SetSpectrumBounds(min, max);
else
channel->SetDisplayBounds(min, max);
}
zoomEnd = zoomStart = 0;
if( pProject )
ProjectHistory::Get( *pProject ).ModifyState(true);
}
enum {
OnZoomFitVerticalID = 20000,
OnZoomResetID,
@ -117,7 +391,7 @@ void WaveTrackVRulerMenuTable::InitMenu(Menu *, void *pUserData)
void WaveTrackVRulerMenuTable::OnZoom( int iZoomCode )
{
WaveTrack::DoZoom
WaveTrackVZoomHandle::DoZoom
(::GetActiveProject(), mpData->pTrack, true,
iZoomCode, mpData->rect, mpData->yy, mpData->yy, false);
@ -402,7 +676,7 @@ UIHandle::Result WaveTrackVZoomHandle::Release
if( bVZoom ){
if( shiftDown )
mZoomStart=mZoomEnd;
WaveTrack::DoZoom(pProject, pTrack.get(), true,
DoZoom(pProject, pTrack.get(), true,
shiftDown ? (rightUp ? kZoom1to1 : kZoomOut) : kZoomIn,
mRect, mZoomStart, mZoomEnd, !shiftDown);
}

View File

@ -16,6 +16,17 @@ class WaveTrack;
#include "../../../../UIHandle.h"
// Note that these can be with or without spectrum view which
// adds a constant.
const int kZoom1to1 = 1;
const int kZoomTimes2 = 2;
const int kZoomDiv2 = 3;
const int kZoomHalfWave = 4;
const int kZoomInByDrag = 5;
const int kZoomIn = 6;
const int kZoomOut = 7;
const int kZoomReset = 8;
class WaveTrackVZoomHandle : public UIHandle
{
WaveTrackVZoomHandle(const WaveTrackVZoomHandle&);
@ -27,6 +38,12 @@ public:
WaveTrackVZoomHandle &operator=(const WaveTrackVZoomHandle&) = default;
static void DoZoom
(AudacityProject *pProject,
WaveTrack *pTrack, bool allChannels, int ZoomKind,
const wxRect &rect, int zoomStart, int zoomEnd,
bool fixedMousePoint);
virtual ~WaveTrackVZoomHandle();
std::shared_ptr<WaveTrack> GetTrack() const { return mpTrack.lock(); }