1
0
mirror of https://github.com/cookiengineer/audacity synced 2025-08-05 22:59:29 +02:00
audacity/src/tracks/playabletrack/wavetrack/ui/WaveTrackVRulerControls.cpp
James Crook 13c6fdf663 VZooming Changes
1: Guard zone 8 pixels wide in VRuler to reduce risk of accidental use.
2: VerticalZooming preference, for VRuler zooming, off by default,
3: Enabled Paul's right-click menu in VRuler with some extra
presets (x2 and x0.5)
4: Rearranged some messy code with lots of ifs to use a switch.

Also, with EXPERIMENTAL_HALF_WAVE defined we now get a
'half wave' option in the VRuler menu, that shows the wave top half.
We also use it in collapsed waves (and collapsing and restoring
a WaveTrack will get you back to normal zoom.
2017-12-11 18:41:48 +00:00

197 lines
6.7 KiB
C++

/**********************************************************************
Audacity: A Digital Audio Editor
WaveTrackVRulerControls.cpp
Paul Licameli split from TrackPanel.cpp
**********************************************************************/
#include "../../../../Audacity.h"
#include "WaveTrackVRulerControls.h"
#include "WaveTrackVZoomHandle.h"
#include "../../../../HitTestResult.h"
#include "../../../../NumberScale.h"
#include "../../../../prefs/SpectrogramSettings.h"
#include "../../../../prefs/WaveformSettings.h"
#include "../../../../Project.h"
#include "../../../../RefreshCode.h"
#include "../../../../TrackPanelMouseEvent.h"
#include "../../../../WaveTrack.h"
///////////////////////////////////////////////////////////////////////////////
WaveTrackVRulerControls::~WaveTrackVRulerControls()
{
}
std::vector<UIHandlePtr> WaveTrackVRulerControls::HitTest
(const TrackPanelMouseState &st,
const AudacityProject *pProject)
{
std::vector<UIHandlePtr> results;
auto pTrack = Track::Pointer<WaveTrack>( FindTrack().get() );
if (pTrack) {
auto result = std::make_shared<WaveTrackVZoomHandle>(
pTrack, st.rect, st.state.m_y );
result = AssignUIHandlePtr(mVZoomHandle, result);
results.push_back(result);
}
auto more = TrackVRulerControls::HitTest(st, pProject);
std::copy(more.begin(), more.end(), std::back_inserter(results));
return results;
}
void WaveTrackVRulerControls::DoZoomPreset( int i)
{
const auto pTrack = FindTrack();
if (!pTrack)
return;
wxASSERT(pTrack->GetKind() == Track::Wave);
const auto wt = static_cast<WaveTrack*>(pTrack.get());
WaveTrackVZoomHandle::DoZoom(
NULL, wt, (i==1)?kZoomHalfWave: kZoom1to1,
wxRect(0,0,0,0), 0,0, true);
}
unsigned WaveTrackVRulerControls::HandleWheelRotation
(const TrackPanelMouseEvent &evt, AudacityProject *pProject)
{
using namespace RefreshCode;
const wxMouseEvent &event = evt.event;
if (!(event.ShiftDown() || event.CmdDown()))
return RefreshNone;
// Always stop propagation even if the ruler didn't change. The ruler
// is a narrow enough target.
evt.event.Skip(false);
const auto pTrack = FindTrack();
if (!pTrack)
return RefreshNone;
wxASSERT(pTrack->GetKind() == Track::Wave);
auto steps = evt.steps;
const auto wt = static_cast<WaveTrack*>(pTrack.get());
// Assume linked track is wave or null
const auto partner = static_cast<WaveTrack*>(wt->GetLink());
const bool isDB =
wt->GetDisplay() == WaveTrack::Waveform &&
wt->GetWaveformSettings().scaleType == WaveformSettings::stLogarithmic;
// Special cases for Waveform dB only.
// Set the bottom of the dB scale but only if it's visible
if (isDB && event.ShiftDown() && event.CmdDown()) {
float min, max;
wt->GetDisplayBounds(&min, &max);
if (!(min < 0.0 && max > 0.0))
return RefreshNone;
WaveformSettings &settings = wt->GetIndependentWaveformSettings();
float olddBRange = settings.dBRange;
if (steps < 0)
// Zoom out
settings.NextLowerDBRange();
else
settings.NextHigherDBRange();
float newdBRange = settings.dBRange;
if (partner) {
WaveformSettings &settings = partner->GetIndependentWaveformSettings();
if (steps < 0)
// Zoom out
settings.NextLowerDBRange();
else
settings.NextHigherDBRange();
}
// Is y coordinate within the rectangle half-height centered about
// the zero level?
const auto &rect = evt.rect;
const auto zeroLevel = wt->ZeroLevelYCoordinate(rect);
const bool fixedMagnification =
(4 * std::abs(event.GetY() - zeroLevel) < rect.GetHeight());
if (fixedMagnification) {
// Vary the db limit without changing
// magnification; that is, peaks and troughs move up and down
// rigidly, as parts of the wave near zero are exposed or hidden.
const float extreme = (LINEAR_TO_DB(2) + newdBRange) / newdBRange;
max = std::min(extreme, max * olddBRange / newdBRange);
min = std::max(-extreme, min * olddBRange / newdBRange);
wt->SetLastdBRange();
wt->SetDisplayBounds(min, max);
if (partner) {
partner->SetLastdBRange();
partner->SetDisplayBounds(min, max);
}
}
}
else if (event.CmdDown() && !event.ShiftDown()) {
const int yy = event.m_y;
WaveTrackVZoomHandle::DoZoom(
pProject, wt, (steps < 0)?kZoomOut:kZoomIn,
evt.rect, yy, yy, true);
}
else if (!event.CmdDown() && event.ShiftDown()) {
// Scroll some fixed number of pixels, independent of zoom level or track height:
static const float movement = 10.0f;
const int height = evt.rect.GetHeight();
const bool spectral = (wt->GetDisplay() == WaveTrack::Spectrum);
if (spectral) {
const float delta = steps * movement / height;
SpectrogramSettings &settings = wt->GetIndependentSpectrogramSettings();
const bool isLinear = settings.scaleType == SpectrogramSettings::stLinear;
float bottom, top;
wt->GetSpectrumBounds(&bottom, &top);
const double rate = wt->GetRate();
const float bound = rate / 2;
const NumberScale numberScale(settings.GetScale(bottom, top));
float newTop =
std::min(bound, numberScale.PositionToValue(1.0f + delta));
const float newBottom =
std::max((isLinear ? 0.0f : 1.0f),
numberScale.PositionToValue(numberScale.ValueToPosition(newTop) - 1.0f));
newTop =
std::min(bound,
numberScale.PositionToValue(numberScale.ValueToPosition(newBottom) + 1.0f));
wt->SetSpectrumBounds(newBottom, newTop);
if (partner)
partner->SetSpectrumBounds(newBottom, newTop);
}
else {
float topLimit = 2.0;
if (isDB) {
const float dBRange = wt->GetWaveformSettings().dBRange;
topLimit = (LINEAR_TO_DB(topLimit) + dBRange) / dBRange;
}
const float bottomLimit = -topLimit;
float top, bottom;
wt->GetDisplayBounds(&bottom, &top);
const float range = top - bottom;
const float delta = range * steps * movement / height;
float newTop = std::min(topLimit, top + delta);
const float newBottom = std::max(bottomLimit, newTop - range);
newTop = std::min(topLimit, newBottom + range);
wt->SetDisplayBounds(newBottom, newTop);
if (partner)
partner->SetDisplayBounds(newBottom, newTop);
}
}
else
return RefreshNone;
pProject->ModifyState(true);
return RefreshCell | UpdateVRuler;
}