Move code for vertical ruler clicks, drags, popup menus, scroll wheel
This commit is contained in:
parent
a313bcdb11
commit
91e6239eeb
|
@ -185,7 +185,6 @@ is time to refresh some aspect of the screen.
|
|||
#include "ondemand/ODManager.h"
|
||||
|
||||
#include "prefs/SpectrogramSettings.h"
|
||||
#include "prefs/WaveformSettings.h"
|
||||
|
||||
#include "toolbars/ControlToolBar.h"
|
||||
#include "toolbars/ToolsToolBar.h"
|
||||
|
@ -193,8 +192,6 @@ is time to refresh some aspect of the screen.
|
|||
// To do: eliminate this!
|
||||
#include "tracks/ui/Scrubbing.h"
|
||||
|
||||
#define ZOOMLIMIT 0.001f
|
||||
|
||||
//This loads the appropriate set of cursors, depending on platform.
|
||||
#include "../images/Cursors.h"
|
||||
|
||||
|
@ -282,18 +279,6 @@ template < class CLIPPEE, class CLIPVAL >
|
|||
|
||||
enum {
|
||||
TrackPanelFirstID = 2000,
|
||||
|
||||
// Reserve an ample block of ids for waveform scale types
|
||||
OnFirstWaveformScaleID,
|
||||
OnLastWaveformScaleID = OnFirstWaveformScaleID + 9,
|
||||
|
||||
// Reserve an ample block of ids for spectrum scale types
|
||||
OnFirstSpectrumScaleID,
|
||||
OnLastSpectrumScaleID = OnFirstSpectrumScaleID + 19,
|
||||
|
||||
OnZoomInVerticalID,
|
||||
OnZoomOutVerticalID,
|
||||
OnZoomFitVerticalID,
|
||||
};
|
||||
|
||||
BEGIN_EVENT_TABLE(TrackPanel, OverlayPanel)
|
||||
|
@ -308,13 +293,6 @@ BEGIN_EVENT_TABLE(TrackPanel, OverlayPanel)
|
|||
EVT_KILL_FOCUS(TrackPanel::OnKillFocus)
|
||||
EVT_CONTEXT_MENU(TrackPanel::OnContextMenu)
|
||||
|
||||
EVT_MENU_RANGE(OnFirstWaveformScaleID, OnLastWaveformScaleID, TrackPanel::OnWaveformScaleType)
|
||||
EVT_MENU_RANGE(OnFirstSpectrumScaleID, OnLastSpectrumScaleID, TrackPanel::OnSpectrumScaleType)
|
||||
|
||||
EVT_MENU(OnZoomInVerticalID, TrackPanel::OnZoomInVertical)
|
||||
EVT_MENU(OnZoomOutVerticalID, TrackPanel::OnZoomOutVertical)
|
||||
EVT_MENU(OnZoomFitVerticalID, TrackPanel::OnZoomFitVertical)
|
||||
|
||||
EVT_TIMER(wxID_ANY, TrackPanel::OnTimer)
|
||||
END_EVENT_TABLE()
|
||||
|
||||
|
@ -389,8 +367,6 @@ TrackPanel::TrackPanel(wxWindow * parent, wxWindowID id,
|
|||
mSelectCursor = MakeCursor( wxCURSOR_IBEAM, IBeamCursorXpm, 17, 16);
|
||||
mEnvelopeCursor= MakeCursor( wxCURSOR_ARROW, EnvCursorXpm, 16, 16);
|
||||
mDisabledCursor= MakeCursor( wxCURSOR_NO_ENTRY, DisabledCursorXpm,16, 16);
|
||||
mZoomInCursor = MakeCursor( wxCURSOR_MAGNIFIER, ZoomInCursorXpm, 19, 15);
|
||||
mZoomOutCursor = MakeCursor( wxCURSOR_MAGNIFIER, ZoomOutCursorXpm, 19, 15);
|
||||
|
||||
#ifdef EXPERIMENTAL_SPECTRAL_EDITING
|
||||
mBottomFrequencyCursor =
|
||||
|
@ -426,9 +402,6 @@ TrackPanel::TrackPanel(wxWindow * parent, wxWindowID id,
|
|||
// Timer is started after the window is visible
|
||||
GetProject()->Bind(wxEVT_IDLE, &TrackPanel::OnIdle, this);
|
||||
|
||||
mZoomStart = -1;
|
||||
mZoomEnd = -1;
|
||||
|
||||
// This is used to snap the cursor to the nearest track that
|
||||
// lines up with it.
|
||||
mSnapManager = NULL;
|
||||
|
@ -510,40 +483,10 @@ void TrackPanel::BuildMenus(void)
|
|||
{
|
||||
// Get rid of existing menus
|
||||
DeleteMenus();
|
||||
|
||||
/*
|
||||
mRulerWaveformMenu = std::make_unique<wxMenu>();
|
||||
BuildVRulerMenuItems
|
||||
(mRulerWaveformMenu.get(), OnFirstWaveformScaleID,
|
||||
WaveformSettings::GetScaleNames());
|
||||
|
||||
mRulerSpectrumMenu = std::make_unique<wxMenu>();
|
||||
BuildVRulerMenuItems
|
||||
(mRulerSpectrumMenu.get(), OnFirstSpectrumScaleID,
|
||||
SpectrogramSettings::GetScaleNames());
|
||||
*/
|
||||
}
|
||||
|
||||
/*
|
||||
// left over from PRL's vertical ruler context menu experiment in 2.1.2
|
||||
// static
|
||||
void TrackPanel::BuildVRulerMenuItems
|
||||
(wxMenu * menu, int firstId, const wxArrayString &names)
|
||||
{
|
||||
int id = firstId;
|
||||
for (int ii = 0, nn = names.size(); ii < nn; ++ii)
|
||||
menu->AppendRadioItem(id++, names[ii]);
|
||||
menu->AppendSeparator();
|
||||
menu->Append(OnZoomInVerticalID, _("Zoom In\tLeft-Click/Left-Drag"));
|
||||
menu->Append(OnZoomOutVerticalID, _("Zoom Out\tShift-Left-Click"));
|
||||
menu->Append(OnZoomFitVerticalID, _("Zoom to Fit\tShift-Right-Click"));
|
||||
}
|
||||
*/
|
||||
|
||||
void TrackPanel::DeleteMenus(void)
|
||||
{
|
||||
mRulerWaveformMenu.reset();
|
||||
mRulerSpectrumMenu.reset();
|
||||
}
|
||||
|
||||
#ifdef EXPERIMENTAL_OUTPUT_DISPLAY
|
||||
|
@ -933,7 +876,6 @@ void TrackPanel::HandleInterruptedDrag()
|
|||
else switch (mMouseCapture)
|
||||
{
|
||||
case IsUncaptured:
|
||||
case IsVZooming:
|
||||
case IsSelecting:
|
||||
case IsSelectingLabelText:
|
||||
case IsResizing:
|
||||
|
@ -1082,8 +1024,6 @@ bool TrackPanel::HandleEscapeKey(bool down)
|
|||
pMixerBoard->Refresh();
|
||||
}
|
||||
break;
|
||||
case IsVZooming:
|
||||
break;
|
||||
case IsResizing:
|
||||
mCapturedTrack->SetHeight(mInitialActualHeight);
|
||||
mCapturedTrack->SetMinimized(mInitialMinimized);
|
||||
|
@ -1230,28 +1170,10 @@ bool TrackPanel::SetCursorByActivity( )
|
|||
|
||||
/// When in the "label" (TrackInfo or vertical ruler), we can either vertical zoom or re-order tracks.
|
||||
/// Dont't change cursor/tip to zoom if display is not waveform (either linear of dB) or Spectrum
|
||||
void TrackPanel::SetCursorAndTipWhenInLabel( Track * t,
|
||||
const wxMouseEvent &event, wxString &tip )
|
||||
void TrackPanel::SetCursorAndTipWhenInLabel( Track * ,
|
||||
const wxMouseEvent &, wxString &tip )
|
||||
{
|
||||
if (event.m_x >= GetVRulerOffset() && (t->GetKind() == Track::Wave) )
|
||||
{
|
||||
tip = _("Click to vertically zoom in. Shift-click to zoom out. Drag to specify a zoom region.");
|
||||
SetCursor(event.ShiftDown()? *mZoomOutCursor : *mZoomInCursor);
|
||||
}
|
||||
#ifdef USE_MIDI
|
||||
else if (event.m_x >= GetVRulerOffset() && t->GetKind() == Track::Note) {
|
||||
tip = _("Click to verticaly zoom in, Shift-click to zoom out, Drag to create a particular zoom region.");
|
||||
SetCursor(event.ShiftDown() ? *mZoomOutCursor : *mZoomInCursor);
|
||||
}
|
||||
#endif
|
||||
else if (event.m_x >= GetVRulerOffset() ){
|
||||
// In VRuler but probably in a label track, and clicks don't do anything here, so no tip.
|
||||
// Use a space for the tip, otherwsie we get he default message.
|
||||
// TODO: Maybe the code for label tracks SHOULD treat the VRuler as part of the TrackInfo?
|
||||
tip = wxT(" ");
|
||||
SetCursor( *mArrowCursor );
|
||||
}
|
||||
else if( GetTrackCount() > 1 ){
|
||||
if( GetTrackCount() > 1 ) {
|
||||
// Set a status message if over TrackInfo.
|
||||
//tip = _("Drag the track vertically to change the order of the tracks.");
|
||||
// i18n-hint: %s is replaced by (translation of) 'Ctrl-Click' on windows, 'Command-Click' on Mac
|
||||
|
@ -2907,12 +2829,6 @@ bool mayDragWidth, bool onlyWithinSnapDistance,
|
|||
}
|
||||
}
|
||||
|
||||
/// Determines if drag zooming is active
|
||||
bool TrackPanel::IsDragZooming(int zoomStart, int zoomEnd)
|
||||
{
|
||||
return (abs(zoomEnd - zoomStart) > DragThreshold);
|
||||
}
|
||||
|
||||
/// Determines if the a modal tool is active
|
||||
bool TrackPanel::IsMouseCaptured()
|
||||
{
|
||||
|
@ -2920,348 +2836,6 @@ bool TrackPanel::IsMouseCaptured()
|
|||
|| mUIHandle != NULL);
|
||||
}
|
||||
|
||||
|
||||
/// Vertical zooming (triggered by clicking in the
|
||||
/// vertical ruler)
|
||||
void TrackPanel::HandleVZoom(wxMouseEvent & event)
|
||||
{
|
||||
if (event.ButtonDown() || event.ButtonDClick()) {
|
||||
HandleVZoomClick( event );
|
||||
}
|
||||
else if (event.Dragging()) {
|
||||
HandleVZoomDrag( event );
|
||||
}
|
||||
else if (event.ButtonUp()) {
|
||||
HandleVZoomButtonUp( event );
|
||||
}
|
||||
//TODO-MB: add timetrack zooming here!
|
||||
}
|
||||
|
||||
/// VZoom click
|
||||
void TrackPanel::HandleVZoomClick( wxMouseEvent & event )
|
||||
{
|
||||
if (mCapturedTrack)
|
||||
return;
|
||||
const auto foundCell = FindCell(event.m_x, event.m_y);
|
||||
mCapturedTrack = foundCell.pTrack;
|
||||
mCapturedRect = foundCell.rect;
|
||||
if (foundCell.type != CellType::VRuler || !(mCapturedTrack = foundCell.pTrack))
|
||||
return;
|
||||
|
||||
if (mCapturedTrack->GetKind() == Track::Wave
|
||||
#ifdef USE_MIDI
|
||||
|| mCapturedTrack->GetKind() == Track::Note
|
||||
#endif
|
||||
)
|
||||
{
|
||||
mMouseCapture = IsVZooming;
|
||||
mZoomStart = event.m_y;
|
||||
mZoomEnd = event.m_y;
|
||||
// change note track to zoom like audio track
|
||||
//#ifdef USE_MIDI
|
||||
// if (mCapturedTrack->GetKind() == Track::Note) {
|
||||
// ((NoteTrack *) mCapturedTrack)->StartVScroll();
|
||||
// }
|
||||
//#endif
|
||||
}
|
||||
}
|
||||
|
||||
/// VZoom drag
|
||||
void TrackPanel::HandleVZoomDrag( wxMouseEvent & event )
|
||||
{
|
||||
mZoomEnd = event.m_y;
|
||||
if (IsDragZooming()){
|
||||
// changed Note track to work like audio track
|
||||
//#ifdef USE_MIDI
|
||||
// if (mCapturedTrack && mCapturedTrack->GetKind() == Track::Note) {
|
||||
// ((NoteTrack *) mCapturedTrack)->VScroll(mZoomStart, mZoomEnd);
|
||||
// }
|
||||
//#endif
|
||||
Refresh(false);
|
||||
}
|
||||
}
|
||||
|
||||
/// VZoom Button up.
|
||||
/// There are three cases:
|
||||
/// - Drag-zooming; we already have a min and max
|
||||
/// - Zoom out; ensure we don't go too small.
|
||||
/// - Zoom in; ensure we don't go too large.
|
||||
void TrackPanel::HandleVZoomButtonUp( wxMouseEvent & event )
|
||||
{
|
||||
if (!mCapturedTrack)
|
||||
return;
|
||||
|
||||
mMouseCapture = IsUncaptured;
|
||||
|
||||
#ifdef USE_MIDI
|
||||
// handle vertical scrolling in Note Track. This is so different from
|
||||
// zooming in audio tracks that it is handled as a special case from
|
||||
// which we then return
|
||||
if (mCapturedTrack->GetKind() == Track::Note) {
|
||||
NoteTrack *nt = (NoteTrack *) mCapturedTrack;
|
||||
const wxRect rect{
|
||||
GetLeftOffset(),
|
||||
mCapturedTrack->GetY() + kTopMargin,
|
||||
GetSize().GetWidth() - GetLeftOffset(),
|
||||
mCapturedTrack->GetHeight() - (kTopMargin + kBottomMargin)
|
||||
};
|
||||
if (IsDragZooming()) {
|
||||
nt->ZoomTo(rect, mZoomStart, mZoomEnd);
|
||||
} else if (event.ShiftDown() || event.RightUp()) {
|
||||
nt->ZoomOut(rect, mZoomEnd);
|
||||
} else {
|
||||
nt->ZoomIn(rect, mZoomEnd);
|
||||
}
|
||||
mZoomEnd = mZoomStart = 0;
|
||||
Refresh(false);
|
||||
mCapturedTrack = NULL;
|
||||
MakeParentModifyState(true);
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
// don't do anything if track is not wave
|
||||
if (mCapturedTrack->GetKind() != Track::Wave)
|
||||
return;
|
||||
|
||||
/*
|
||||
if (event.RightUp() &&
|
||||
!(event.ShiftDown() || event.CmdDown())) {
|
||||
OnVRulerMenu(mCapturedTrack, &event);
|
||||
return;
|
||||
}
|
||||
*/
|
||||
|
||||
HandleWaveTrackVZoom(static_cast<WaveTrack*>(mCapturedTrack),
|
||||
event.ShiftDown(), event.RightUp());
|
||||
mCapturedTrack = NULL;
|
||||
}
|
||||
|
||||
void TrackPanel::HandleWaveTrackVZoom(WaveTrack *track, bool shiftDown, bool rightUp)
|
||||
{
|
||||
HandleWaveTrackVZoom(GetTracks(), mCapturedRect, mZoomStart, mZoomEnd,
|
||||
track, shiftDown, rightUp, false);
|
||||
mZoomEnd = mZoomStart = 0;
|
||||
UpdateVRuler(track);
|
||||
Refresh(false);
|
||||
MakeParentModifyState(true);
|
||||
}
|
||||
|
||||
//static
|
||||
void TrackPanel::HandleWaveTrackVZoom
|
||||
(TrackList *tracks, const wxRect &rect,
|
||||
int zoomStart, int zoomEnd,
|
||||
WaveTrack *track, bool shiftDown, bool rightUp,
|
||||
bool fixedMousePoint)
|
||||
{
|
||||
// Assume linked track is wave or null
|
||||
const auto partner = static_cast<WaveTrack *>(track->GetLink());
|
||||
int height = track->GetHeight() - (kTopMargin + kBottomMargin);
|
||||
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 = track->GetRate();
|
||||
const float halfrate = rate / 2;
|
||||
const SpectrogramSettings &settings = track->GetSpectrogramSettings();
|
||||
NumberScale scale;
|
||||
const bool spectral = (track->GetDisplay() == WaveTrack::Spectrum);
|
||||
const bool spectrumLinear = spectral &&
|
||||
(track->GetSpectrogramSettings().scaleType == SpectrogramSettings::stLinear);
|
||||
|
||||
if (spectral) {
|
||||
track->GetSpectrumBounds(&min, &max);
|
||||
scale = settings.GetScale( min, max );
|
||||
const auto fftLength = settings.GetFFTLength();
|
||||
const float binSize = rate / fftLength;
|
||||
|
||||
// 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
|
||||
track->GetDisplayBounds(&min, &max);
|
||||
|
||||
if (IsDragZooming(zoomStart, zoomEnd)) {
|
||||
// Drag Zoom
|
||||
const float tmin = min, tmax = max;
|
||||
|
||||
if (spectral) {
|
||||
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)
|
||||
));
|
||||
}
|
||||
else {
|
||||
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...
|
||||
const 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;
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (shiftDown || rightUp) {
|
||||
// Zoom OUT
|
||||
if (spectral) {
|
||||
if (shiftDown && rightUp) {
|
||||
// Zoom out full
|
||||
min = spectrumLinear ? 0.0f : 1.0f;
|
||||
max = halfrate;
|
||||
}
|
||||
else {
|
||||
// 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));
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
// Zoom out to -1.0...1.0 first, then, and only
|
||||
// then, if they click again, allow one more
|
||||
// zoom out.
|
||||
if (shiftDown && rightUp) {
|
||||
// Zoom out full
|
||||
min = -1.0;
|
||||
max = 1.0;
|
||||
}
|
||||
else {
|
||||
// Zoom out
|
||||
const WaveformSettings &settings = track->GetWaveformSettings();
|
||||
const bool linear = settings.isLinear();
|
||||
const float top = linear
|
||||
? 2.0
|
||||
: (LINEAR_TO_DB(2.0) + settings.dBRange) / settings.dBRange;
|
||||
if (min <= -1.0 && max >= 1.0) {
|
||||
// Go to the maximal zoom-out
|
||||
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));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
// Zoom IN
|
||||
if (spectral) {
|
||||
// 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)
|
||||
));
|
||||
}
|
||||
}
|
||||
else {
|
||||
// Zoom in centered on cursor
|
||||
if (min < -1.0 || max > 1.0) {
|
||||
min = -1.0;
|
||||
max = 1.0;
|
||||
}
|
||||
else {
|
||||
// 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;
|
||||
const 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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (spectral) {
|
||||
track->SetSpectrumBounds(min, max);
|
||||
if (partner)
|
||||
partner->SetSpectrumBounds(min, max);
|
||||
}
|
||||
else {
|
||||
track->SetDisplayBounds(min, max);
|
||||
if (partner)
|
||||
partner->SetDisplayBounds(min, max);
|
||||
}
|
||||
}
|
||||
|
||||
void TrackPanel::UpdateViewIfNoTracks()
|
||||
{
|
||||
if (mTracks->IsEmpty())
|
||||
|
@ -3986,20 +3560,6 @@ void TrackPanel::HandleWheelRotation(wxMouseEvent & event)
|
|||
// you do see changes in the time ruler.
|
||||
return;
|
||||
|
||||
// Special case of pointer in the vertical ruler
|
||||
if (event.ShiftDown() || event.CmdDown()) {
|
||||
const auto foundCell = FindCell(event.m_x, event.m_y);
|
||||
auto &pTrack = foundCell.pTrack;
|
||||
auto &rect = foundCell.rect;
|
||||
if (pTrack && foundCell.type == CellType::VRuler) {
|
||||
HandleWheelRotationInVRuler(event, steps, pTrack, rect);
|
||||
// Always stop propagation even if the ruler didn't change. The ruler
|
||||
// is a narrow enough target.
|
||||
event.Skip(false);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (event.ShiftDown()
|
||||
// Don't pan during smooth scrolling. That would conflict with keeping
|
||||
// the play indicator centered.
|
||||
|
@ -4083,128 +3643,6 @@ void TrackPanel::HandleWheelRotation(wxMouseEvent & event)
|
|||
}
|
||||
}
|
||||
|
||||
void TrackPanel::HandleWheelRotationInVRuler
|
||||
(wxMouseEvent &event, double steps, Track *pTrack, const wxRect &rect)
|
||||
{
|
||||
if (pTrack->GetKind() == Track::Wave) {
|
||||
WaveTrack *const wt = static_cast<WaveTrack*>(pTrack);
|
||||
// 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) {
|
||||
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 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()) {
|
||||
HandleWaveTrackVZoom(
|
||||
GetTracks(), rect, event.m_y, event.m_y,
|
||||
wt, false, (steps < 0),
|
||||
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 = wt->GetHeight() - (kTopMargin + kBottomMargin);
|
||||
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;
|
||||
|
||||
UpdateVRuler(pTrack);
|
||||
Refresh(false);
|
||||
MakeParentModifyState(true);
|
||||
}
|
||||
else {
|
||||
// To do: time track? Note track?
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
/// Filter captured keys typed into LabelTracks.
|
||||
void TrackPanel::OnCaptureKey(wxCommandEvent & event)
|
||||
{
|
||||
|
@ -4517,9 +3955,6 @@ try
|
|||
}
|
||||
}
|
||||
else switch( mMouseCapture ) {
|
||||
case IsVZooming:
|
||||
HandleVZoom(event);
|
||||
break;
|
||||
case IsResizing:
|
||||
case IsResizingBetweenLinkedTracks:
|
||||
case IsResizingBelowLinkedTracks:
|
||||
|
@ -4794,8 +4229,6 @@ void TrackPanel::HandleTrackSpecificMouseEvent(wxMouseEvent & event)
|
|||
|
||||
else {
|
||||
if (foundCell.type == CellType::VRuler) {
|
||||
if (!event.Dragging()) // JKC: Only want the mouse down event.
|
||||
HandleVZoom(event);
|
||||
}
|
||||
else if (foundCell.type == CellType::Label)
|
||||
HandleLabelClick(event);
|
||||
|
@ -5139,15 +4572,6 @@ void TrackPanel::DrawEverythingElse(wxDC * dc,
|
|||
if (mUIHandle)
|
||||
mUIHandle->DrawExtras(UIHandle::Cells, dc, region, clip);
|
||||
|
||||
if (mMouseCapture == IsVZooming && IsDragZooming()
|
||||
// note track zooming now works like audio track
|
||||
//#ifdef USE_MIDI
|
||||
// && mCapturedTrack && mCapturedTrack->GetKind() != Track::Note
|
||||
//#endif
|
||||
) {
|
||||
DrawZooming(dc, clip);
|
||||
}
|
||||
|
||||
// Paint over the part below the tracks
|
||||
trackRect.y += trackRect.height;
|
||||
if (trackRect.y < clip.GetBottom()) {
|
||||
|
@ -5176,35 +4600,6 @@ void TrackPanel::DrawEverythingElse(wxDC * dc,
|
|||
mSnapManager->Draw( dc, GetSnapLeft(), GetSnapRight() );
|
||||
}
|
||||
|
||||
/// Draw zooming indicator that shows the region that will
|
||||
/// be zoomed into when the user clicks and drags with a
|
||||
/// zoom cursor. Handles both vertical and horizontal
|
||||
/// zooming.
|
||||
void TrackPanel::DrawZooming(wxDC * dc, const wxRect & clip)
|
||||
{
|
||||
wxRect rect;
|
||||
|
||||
dc->SetBrush(*wxTRANSPARENT_BRUSH);
|
||||
dc->SetPen(*wxBLACK_DASHED_PEN);
|
||||
|
||||
if (mMouseCapture==IsVZooming) {
|
||||
rect.y = std::min(mZoomStart, mZoomEnd);
|
||||
rect.height = 1 + abs(mZoomEnd - mZoomStart);
|
||||
|
||||
rect.x = GetVRulerOffset();
|
||||
rect.SetRight(GetSize().x - kRightMargin); // extends into border rect
|
||||
}
|
||||
else {
|
||||
rect.x = std::min(mZoomStart, mZoomEnd);
|
||||
rect.width = 1 + abs(mZoomEnd - mZoomStart);
|
||||
|
||||
rect.y = -1;
|
||||
rect.height = clip.height + 2;
|
||||
}
|
||||
|
||||
dc->DrawRectangle(rect);
|
||||
}
|
||||
|
||||
// Make this #include go away!
|
||||
#include "tracks/ui/TrackControls.h"
|
||||
|
||||
|
@ -5806,56 +5201,6 @@ void TrackPanel::OnTrackMenu(Track *t)
|
|||
Refresh(false);
|
||||
}
|
||||
|
||||
void TrackPanel::OnVRulerMenu(Track *t, wxMouseEvent *pEvent)
|
||||
{
|
||||
if (!t) {
|
||||
t = GetFocusedTrack();
|
||||
if (!t)
|
||||
return;
|
||||
}
|
||||
|
||||
if (t->GetKind() != Track::Wave)
|
||||
return;
|
||||
|
||||
WaveTrack *const wt = static_cast<WaveTrack*>(t);
|
||||
|
||||
const int display = wt->GetDisplay();
|
||||
wxMenu *theMenu;
|
||||
if (display == WaveTrack::Waveform) {
|
||||
theMenu = mRulerWaveformMenu.get();
|
||||
const int id =
|
||||
OnFirstWaveformScaleID + (int)(wt->GetWaveformSettings().scaleType);
|
||||
theMenu->Check(id, true);
|
||||
}
|
||||
else {
|
||||
theMenu = mRulerSpectrumMenu.get();
|
||||
const int id =
|
||||
OnFirstSpectrumScaleID + (int)(wt->GetSpectrogramSettings().scaleType);
|
||||
theMenu->Check(id, true);
|
||||
}
|
||||
|
||||
int x, y;
|
||||
if (pEvent)
|
||||
x = pEvent->m_x, y = pEvent->m_y;
|
||||
else {
|
||||
// If no event given, pop up the menu at the same height
|
||||
// as for the track control menu
|
||||
const wxRect rect = FindTrackRect(wt, true);
|
||||
wxRect titleRect;
|
||||
mTrackInfo.GetTitleBarRect(rect, titleRect);
|
||||
x = GetVRulerOffset(), y = titleRect.y + titleRect.height + 1;
|
||||
}
|
||||
|
||||
// So that IsDragZooming() returns false, and if we zoom in, we do so
|
||||
// centered where the mouse is now:
|
||||
mZoomStart = mZoomEnd = pEvent->m_y;
|
||||
|
||||
mPopupMenuTarget = wt;
|
||||
PopupMenu(theMenu, x, y);
|
||||
mPopupMenuTarget = NULL;
|
||||
}
|
||||
|
||||
|
||||
Track * TrackPanel::GetFirstSelectedTrack()
|
||||
{
|
||||
|
||||
|
@ -5994,68 +5339,6 @@ void TrackPanel::DrawShadow(Track * /* t */ , wxDC * dc, const wxRect & rect)
|
|||
AColor::Line(*dc, right, rect.y, right, rect.y + 1);
|
||||
}
|
||||
|
||||
void TrackPanel::OnWaveformScaleType(wxCommandEvent &evt)
|
||||
{
|
||||
// Get here only from vertical ruler menu for wave tracks
|
||||
const auto wt = static_cast<WaveTrack *>(mPopupMenuTarget);
|
||||
// Assume linked track is wave or null
|
||||
const auto partner = static_cast<WaveTrack*>(wt->GetLink());
|
||||
const WaveformSettings::ScaleType newScaleType =
|
||||
WaveformSettings::ScaleType(
|
||||
std::max(0,
|
||||
std::min((int)(WaveformSettings::stNumScaleTypes) - 1,
|
||||
evt.GetId() - OnFirstWaveformScaleID
|
||||
)));
|
||||
if (wt->GetWaveformSettings().scaleType != newScaleType) {
|
||||
wt->GetIndependentWaveformSettings().scaleType = newScaleType;
|
||||
if (partner)
|
||||
partner->GetIndependentWaveformSettings().scaleType = newScaleType;
|
||||
UpdateVRuler(wt); // Is this really needed?
|
||||
MakeParentModifyState(true);
|
||||
Refresh(false);
|
||||
}
|
||||
}
|
||||
|
||||
void TrackPanel::OnSpectrumScaleType(wxCommandEvent &evt)
|
||||
{
|
||||
// Get here only from vertical ruler menu for wave tracks
|
||||
const auto wt = static_cast<WaveTrack *>(mPopupMenuTarget);
|
||||
// Assume linked track is wave or null
|
||||
const auto partner = static_cast<WaveTrack*>(wt->GetLink());
|
||||
const SpectrogramSettings::ScaleType newScaleType =
|
||||
SpectrogramSettings::ScaleType(
|
||||
std::max(0,
|
||||
std::min((int)(SpectrogramSettings::stNumScaleTypes) - 1,
|
||||
evt.GetId() - OnFirstSpectrumScaleID
|
||||
)));
|
||||
if (wt->GetSpectrogramSettings().scaleType != newScaleType) {
|
||||
wt->GetIndependentSpectrogramSettings().scaleType = newScaleType;
|
||||
if (partner)
|
||||
partner->GetIndependentSpectrogramSettings().scaleType = newScaleType;
|
||||
UpdateVRuler(wt); // Is this really needed?
|
||||
MakeParentModifyState(true);
|
||||
Refresh(false);
|
||||
}
|
||||
}
|
||||
|
||||
void TrackPanel::OnZoomInVertical(wxCommandEvent &)
|
||||
{
|
||||
// Get here only from vertical ruler menu for wave tracks
|
||||
HandleWaveTrackVZoom(static_cast<WaveTrack*>(mPopupMenuTarget), false, false);
|
||||
}
|
||||
|
||||
void TrackPanel::OnZoomOutVertical(wxCommandEvent &)
|
||||
{
|
||||
// Get here only from vertical ruler menu for wave tracks
|
||||
HandleWaveTrackVZoom(static_cast<WaveTrack*>(mPopupMenuTarget), true, false);
|
||||
}
|
||||
|
||||
void TrackPanel::OnZoomFitVertical(wxCommandEvent &)
|
||||
{
|
||||
// Get here only from vertical ruler menu for wave tracks
|
||||
HandleWaveTrackVZoom(static_cast<WaveTrack*>(mPopupMenuTarget), true, true);
|
||||
}
|
||||
|
||||
/// Determines which cell is under the mouse
|
||||
/// @param mouseX - mouse X position.
|
||||
/// @param mouseY - mouse Y position.
|
||||
|
|
|
@ -317,7 +317,6 @@ class AUDACITY_DLL_API TrackPanel final : public OverlayPanel {
|
|||
virtual void ScrollIntoView(int x);
|
||||
|
||||
virtual void OnTrackMenu(Track *t = NULL);
|
||||
virtual void OnVRulerMenu(Track *t, wxMouseEvent *pEvent = NULL);
|
||||
virtual Track * GetFirstSelectedTrack();
|
||||
virtual bool IsMouseCaptured();
|
||||
|
||||
|
@ -340,9 +339,6 @@ class AUDACITY_DLL_API TrackPanel final : public OverlayPanel {
|
|||
protected:
|
||||
virtual MixerBoard* GetMixerBoard();
|
||||
|
||||
// left over from PRL's vertical ruler context menu experiment in 2.1.2
|
||||
// static void BuildVRulerMenuItems(wxMenu * menu, int firstId, const wxArrayString &names);
|
||||
|
||||
virtual bool IsAudioActive();
|
||||
virtual bool IsUnsafe();
|
||||
virtual bool HandleLabelTrackClick(LabelTrack * lTrack, const wxRect &rect, wxMouseEvent & event);
|
||||
|
@ -447,24 +443,8 @@ public:
|
|||
protected:
|
||||
virtual void MaySetOnDemandTip( Track * t, wxString &tip );
|
||||
|
||||
static bool IsDragZooming(int zoomStart, int zoomEnd);
|
||||
virtual bool IsDragZooming() { return IsDragZooming(mZoomStart, mZoomEnd); }
|
||||
|
||||
virtual void HandleVZoom(wxMouseEvent & event);
|
||||
virtual void HandleVZoomClick(wxMouseEvent & event);
|
||||
virtual void HandleVZoomDrag(wxMouseEvent & event);
|
||||
virtual void HandleVZoomButtonUp(wxMouseEvent & event);
|
||||
virtual void HandleWaveTrackVZoom(WaveTrack *track, bool shiftDown, bool rightUp);
|
||||
static void HandleWaveTrackVZoom
|
||||
(TrackList *tracks, const wxRect &rect,
|
||||
int zoomStart, int zoomEnd,
|
||||
WaveTrack *track, bool shiftDown, bool rightUp,
|
||||
bool fixedMousePoint);
|
||||
|
||||
// MM: Handle mouse wheel rotation
|
||||
virtual void HandleWheelRotation(wxMouseEvent & event);
|
||||
virtual void HandleWheelRotationInVRuler
|
||||
(wxMouseEvent &event, double steps, Track *pTrack, const wxRect &rect);
|
||||
|
||||
// Handle resizing.
|
||||
virtual void HandleResizeClick(wxMouseEvent & event);
|
||||
|
@ -488,13 +468,6 @@ protected:
|
|||
virtual void MakeParentModifyState(bool bWantsAutoSave); // if true, writes auto-save file. Should set only if you really want the state change restored after
|
||||
// a crash, as it can take many seconds for large (eg. 10 track-hours) projects
|
||||
|
||||
virtual void OnWaveformScaleType(wxCommandEvent &event);
|
||||
virtual void OnSpectrumScaleType(wxCommandEvent &event);
|
||||
|
||||
virtual void OnZoomInVertical(wxCommandEvent &event);
|
||||
virtual void OnZoomOutVertical(wxCommandEvent &event);
|
||||
virtual void OnZoomFitVertical(wxCommandEvent &event);
|
||||
|
||||
// Find track info by coordinate
|
||||
enum class CellType { Label, Track, VRuler, Background };
|
||||
struct FoundCell {
|
||||
|
@ -539,7 +512,6 @@ protected:
|
|||
virtual void DrawEverythingElse(wxDC *dc, const wxRegion & region,
|
||||
const wxRect & clip);
|
||||
virtual void DrawOutside(Track *t, wxDC *dc, const wxRect & rec);
|
||||
virtual void DrawZooming(wxDC* dc, const wxRect & clip);
|
||||
|
||||
virtual void HighlightFocusedTrack (wxDC* dc, const wxRect &rect);
|
||||
virtual void DrawShadow (Track *t, wxDC* dc, const wxRect & rect);
|
||||
|
@ -653,9 +625,6 @@ protected:
|
|||
int mMouseMostRecentX;
|
||||
int mMouseMostRecentY;
|
||||
|
||||
int mZoomStart;
|
||||
int mZoomEnd;
|
||||
|
||||
// Handles snapping the selection boundaries or track boundaries to
|
||||
// line up with existing tracks or labels. mSnapLeft and mSnapRight
|
||||
// are the horizontal index of pixels to display user feedback
|
||||
|
@ -725,7 +694,6 @@ public:
|
|||
enum MouseCaptureEnum
|
||||
{
|
||||
IsUncaptured=0, // This is the normal state for the mouse
|
||||
IsVZooming,
|
||||
IsClosing,
|
||||
IsSelecting,
|
||||
IsAdjustingLabel,
|
||||
|
@ -755,7 +723,6 @@ protected:
|
|||
mArrowCursor, mSelectCursor,
|
||||
mResizeCursor, mEnvelopeCursor, // doubles as the center frequency cursor
|
||||
// for spectral selection
|
||||
mZoomInCursor, mZoomOutCursor,
|
||||
mRearrangeCursor,
|
||||
mDisabledCursor, mAdjustLeftSelectionCursor, mAdjustRightSelectionCursor;
|
||||
#ifdef EXPERIMENTAL_SPECTRAL_EDITING
|
||||
|
@ -767,9 +734,6 @@ protected:
|
|||
mStretchCursor, mStretchLeftCursor, mStretchRightCursor;
|
||||
#endif
|
||||
|
||||
std::unique_ptr<wxMenu>
|
||||
mRulerWaveformMenu, mRulerSpectrumMenu;
|
||||
|
||||
Track *mPopupMenuTarget {};
|
||||
|
||||
friend class TrackPanelAx;
|
||||
|
|
|
@ -76,6 +76,7 @@ class NoteTrackMenuTable : public PopupMenuTable
|
|||
public:
|
||||
static NoteTrackMenuTable &Instance();
|
||||
|
||||
private:
|
||||
void InitMenu(Menu*, void *pUserData) override
|
||||
{
|
||||
mpData = static_cast<TrackControls::InitMenuData*>(pUserData);
|
||||
|
|
|
@ -13,8 +13,193 @@ Paul Licameli split from TrackPanel.cpp
|
|||
#ifdef USE_MIDI
|
||||
|
||||
#include "NoteTrackVRulerControls.h"
|
||||
#include "../../../../HitTestResult.h"
|
||||
|
||||
#include "../../../../HitTestResult.h"
|
||||
#include "../../../../NoteTrack.h"
|
||||
#include "../../../../Project.h"
|
||||
#include "../../../../RefreshCode.h"
|
||||
#include "../../../../TrackPanelMouseEvent.h"
|
||||
#include "../../../../UIHandle.h"
|
||||
#include "../../../../../images/Cursors.h"
|
||||
|
||||
namespace
|
||||
{
|
||||
|
||||
bool IsDragZooming(int zoomStart, int zoomEnd)
|
||||
{
|
||||
const int DragThreshold = 3;// Anything over 3 pixels is a drag, else a click.
|
||||
return (abs(zoomEnd - zoomStart) > DragThreshold);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
class NoteTrackVZoomHandle : public UIHandle
|
||||
{
|
||||
NoteTrackVZoomHandle();
|
||||
NoteTrackVZoomHandle(const NoteTrackVZoomHandle&);
|
||||
NoteTrackVZoomHandle &operator=(const NoteTrackVZoomHandle&);
|
||||
static NoteTrackVZoomHandle& Instance();
|
||||
static HitTestPreview HitPreview(const wxMouseEvent &event);
|
||||
|
||||
public:
|
||||
static HitTestResult HitTest(const wxMouseEvent &event);
|
||||
|
||||
virtual ~NoteTrackVZoomHandle();
|
||||
|
||||
virtual Result Click
|
||||
(const TrackPanelMouseEvent &event, AudacityProject *pProject);
|
||||
|
||||
virtual Result Drag
|
||||
(const TrackPanelMouseEvent &event, AudacityProject *pProject);
|
||||
|
||||
virtual HitTestPreview Preview
|
||||
(const TrackPanelMouseEvent &event, const AudacityProject *pProject);
|
||||
|
||||
virtual Result Release
|
||||
(const TrackPanelMouseEvent &event, AudacityProject *pProject,
|
||||
wxWindow *pParent);
|
||||
|
||||
virtual Result Cancel(AudacityProject *pProject);
|
||||
|
||||
virtual void DrawExtras
|
||||
(DrawingPass pass,
|
||||
wxDC * dc, const wxRegion &updateRegion, const wxRect &panelRect);
|
||||
|
||||
void OnProjectChange(AudacityProject *pProject) override;
|
||||
|
||||
private:
|
||||
NoteTrack *mpTrack;
|
||||
|
||||
int mZoomStart, mZoomEnd;
|
||||
wxRect mRect;
|
||||
};
|
||||
|
||||
NoteTrackVZoomHandle::NoteTrackVZoomHandle()
|
||||
: mpTrack(NULL), mZoomStart(0), mZoomEnd(0), mRect()
|
||||
{
|
||||
}
|
||||
|
||||
NoteTrackVZoomHandle &NoteTrackVZoomHandle::Instance()
|
||||
{
|
||||
static NoteTrackVZoomHandle instance;
|
||||
return instance;
|
||||
}
|
||||
|
||||
HitTestPreview NoteTrackVZoomHandle::HitPreview(const wxMouseEvent &event)
|
||||
{
|
||||
static auto zoomInCursor =
|
||||
::MakeCursor(wxCURSOR_MAGNIFIER, ZoomInCursorXpm, 19, 15);
|
||||
static auto zoomOutCursor =
|
||||
::MakeCursor(wxCURSOR_MAGNIFIER, ZoomOutCursorXpm, 19, 15);
|
||||
return {
|
||||
_("Click to verticaly zoom in, Shift-click to zoom out, Drag to create a particular zoom region."),
|
||||
(event.ShiftDown() ? &*zoomOutCursor : &*zoomInCursor)
|
||||
};
|
||||
}
|
||||
|
||||
HitTestResult NoteTrackVZoomHandle::HitTest(const wxMouseEvent &event)
|
||||
{
|
||||
return HitTestResult(HitPreview(event), &Instance());
|
||||
}
|
||||
|
||||
NoteTrackVZoomHandle::~NoteTrackVZoomHandle()
|
||||
{
|
||||
}
|
||||
|
||||
UIHandle::Result NoteTrackVZoomHandle::Click
|
||||
(const TrackPanelMouseEvent &evt, AudacityProject *pProject)
|
||||
{
|
||||
mpTrack = static_cast<NoteTrack*>(
|
||||
static_cast<NoteTrackVRulerControls*>(evt.pCell)->GetTrack()
|
||||
);
|
||||
mRect = evt.rect;
|
||||
|
||||
const wxMouseEvent &event = evt.event;
|
||||
mZoomStart = event.m_y;
|
||||
mZoomEnd = event.m_y;
|
||||
|
||||
// change note track to zoom like audio track
|
||||
// mpTrack->StartVScroll();
|
||||
|
||||
return RefreshCode::RefreshNone;
|
||||
}
|
||||
|
||||
UIHandle::Result NoteTrackVZoomHandle::Drag
|
||||
(const TrackPanelMouseEvent &evt, AudacityProject *pProject)
|
||||
{
|
||||
const wxMouseEvent &event = evt.event;
|
||||
mZoomEnd = event.m_y;
|
||||
using namespace RefreshCode;
|
||||
if (IsDragZooming(mZoomStart, mZoomEnd)) {
|
||||
// changed Note track to work like audio track
|
||||
// mpTrack->VScroll(mZoomStart, mZoomEnd);
|
||||
return RefreshAll;
|
||||
}
|
||||
return RefreshNone;
|
||||
}
|
||||
|
||||
HitTestPreview NoteTrackVZoomHandle::Preview
|
||||
(const TrackPanelMouseEvent &evt, const AudacityProject *pProject)
|
||||
{
|
||||
return HitPreview(evt.event);
|
||||
}
|
||||
|
||||
UIHandle::Result NoteTrackVZoomHandle::Release
|
||||
(const TrackPanelMouseEvent &evt, AudacityProject *pProject,
|
||||
wxWindow *pParent)
|
||||
{
|
||||
using namespace RefreshCode;
|
||||
if (!mpTrack)
|
||||
return RefreshNone;
|
||||
|
||||
const wxMouseEvent &event = evt.event;
|
||||
if (IsDragZooming(mZoomStart, mZoomEnd)) {
|
||||
mpTrack->ZoomTo(evt.rect, mZoomStart, mZoomEnd);
|
||||
}
|
||||
else if (event.ShiftDown() || event.RightUp()) {
|
||||
mpTrack->ZoomOut(evt.rect, mZoomEnd);
|
||||
}
|
||||
else {
|
||||
mpTrack->ZoomIn(evt.rect, mZoomEnd);
|
||||
}
|
||||
|
||||
// TODO: shift-right click as in audio track?
|
||||
|
||||
mZoomEnd = mZoomStart = 0;
|
||||
pProject->ModifyState(true);
|
||||
|
||||
return RefreshAll;
|
||||
}
|
||||
|
||||
UIHandle::Result NoteTrackVZoomHandle::Cancel(AudacityProject *pProject)
|
||||
{
|
||||
// Cancel is implemented! And there is no initial state to restore,
|
||||
// so just return a code.
|
||||
return RefreshCode::RefreshAll;
|
||||
}
|
||||
|
||||
void NoteTrackVZoomHandle::DrawExtras
|
||||
(DrawingPass pass, wxDC * dc, const wxRegion &, const wxRect &panelRect)
|
||||
{
|
||||
if ( pass == UIHandle::Cells &&
|
||||
IsDragZooming( mZoomStart, mZoomEnd ) )
|
||||
TrackVRulerControls::DrawZooming
|
||||
( dc, mRect, panelRect, mZoomStart, mZoomEnd );
|
||||
}
|
||||
|
||||
void NoteTrackVZoomHandle::OnProjectChange(AudacityProject *pProject)
|
||||
{
|
||||
if (! pProject->GetTracks()->Contains(mpTrack)) {
|
||||
mpTrack = nullptr;
|
||||
mRect = {};
|
||||
}
|
||||
|
||||
UIHandle::OnProjectChange(pProject);
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
NoteTrackVRulerControls::NoteTrackVRulerControls()
|
||||
: TrackVRulerControls()
|
||||
{
|
||||
|
@ -31,10 +216,14 @@ NoteTrackVRulerControls::~NoteTrackVRulerControls()
|
|||
}
|
||||
|
||||
HitTestResult NoteTrackVRulerControls::HitTest
|
||||
(const TrackPanelMouseEvent &,
|
||||
(const TrackPanelMouseEvent &evt,
|
||||
const AudacityProject *)
|
||||
{
|
||||
#ifdef USE_MIDI
|
||||
return NoteTrackVZoomHandle::HitTest(evt.event);
|
||||
#else
|
||||
return {};
|
||||
#endif
|
||||
}
|
||||
|
||||
#endif
|
|
@ -10,8 +10,652 @@ Paul Licameli split from TrackPanel.cpp
|
|||
|
||||
#include "../../../../Audacity.h"
|
||||
#include "WaveTrackVRulerControls.h"
|
||||
#include "../../../../HitTestResult.h"
|
||||
|
||||
#include <algorithm>
|
||||
|
||||
#include "../../../../HitTestResult.h"
|
||||
#include "../../../../NumberScale.h"
|
||||
#include "../../../../prefs/SpectrogramSettings.h"
|
||||
#include "../../../../prefs/WaveformSettings.h"
|
||||
#include "../../../../Project.h"
|
||||
#include "../../../../RefreshCode.h"
|
||||
#include "../../../../TrackPanelMouseEvent.h"
|
||||
#include "../../../../UIHandle.h"
|
||||
#include "../../../../WaveTrack.h"
|
||||
#include "../../../../widgets/PopupMenuTable.h"
|
||||
#include "../../../../../images/Cursors.h"
|
||||
|
||||
#include <wx/gdicmn.h>
|
||||
#include <wx/dc.h>
|
||||
|
||||
|
||||
namespace
|
||||
{
|
||||
|
||||
struct InitMenuData
|
||||
{
|
||||
public:
|
||||
WaveTrack *pTrack;
|
||||
wxRect rect;
|
||||
unsigned result;
|
||||
int yy;
|
||||
};
|
||||
|
||||
bool IsDragZooming(int zoomStart, int zoomEnd)
|
||||
{
|
||||
const int DragThreshold = 3;// Anything over 3 pixels is a drag, else a click.
|
||||
return (abs(zoomEnd - zoomStart) > DragThreshold);
|
||||
}
|
||||
|
||||
void HandleWaveTrackVZoom
|
||||
(AudacityProject *pProject,
|
||||
WaveTrack *pTrack, bool shiftDown, bool rightUp,
|
||||
const wxRect &rect, int zoomStart, int zoomEnd,
|
||||
bool fixedMousePoint)
|
||||
{
|
||||
static const float ZOOMLIMIT = 0.001f;
|
||||
|
||||
TrackList *const tracks = pProject->GetTracks();
|
||||
|
||||
// Assume linked track is wave or null
|
||||
const auto partner = static_cast<WaveTrack *>(pTrack->GetLink());
|
||||
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, c, minBand = 0;
|
||||
const double rate = pTrack->GetRate();
|
||||
const float halfrate = rate / 2;
|
||||
const SpectrogramSettings &settings = pTrack->GetSpectrogramSettings();
|
||||
NumberScale scale;
|
||||
const bool spectral = (pTrack->GetDisplay() == WaveTrack::Spectrum);
|
||||
const bool spectrumLinear = spectral &&
|
||||
(pTrack->GetSpectrogramSettings().scaleType == SpectrogramSettings::stLinear);
|
||||
|
||||
if (spectral) {
|
||||
pTrack->GetSpectrumBounds(&min, &max);
|
||||
scale = (settings.GetScale(min, max));
|
||||
const auto fftLength = settings.GetFFTLength();
|
||||
const float binSize = rate / fftLength;
|
||||
|
||||
// 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);
|
||||
|
||||
if (IsDragZooming(zoomStart, zoomEnd)) {
|
||||
// Drag Zoom
|
||||
const float tmin = min, tmax = max;
|
||||
|
||||
if (spectral) {
|
||||
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)
|
||||
));
|
||||
}
|
||||
else {
|
||||
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...
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (shiftDown || rightUp) {
|
||||
// Zoom OUT
|
||||
if (spectral) {
|
||||
if (shiftDown && rightUp) {
|
||||
// Zoom out full
|
||||
min = spectrumLinear ? 0.0f : 1.0f;
|
||||
max = halfrate;
|
||||
}
|
||||
else {
|
||||
// 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));
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
// Zoom out to -1.0...1.0 first, then, and only
|
||||
// then, if they click again, allow one more
|
||||
// zoom out.
|
||||
if (shiftDown && rightUp) {
|
||||
// Zoom out full
|
||||
min = -1.0;
|
||||
max = 1.0;
|
||||
}
|
||||
else {
|
||||
// Zoom out
|
||||
const WaveformSettings &settings = pTrack->GetWaveformSettings();
|
||||
const bool linear = settings.isLinear();
|
||||
const float top = linear
|
||||
? 2.0
|
||||
: (LINEAR_TO_DB(2.0) + settings.dBRange) / settings.dBRange;
|
||||
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));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
// Zoom IN
|
||||
if (spectral) {
|
||||
// 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)
|
||||
));
|
||||
}
|
||||
}
|
||||
else {
|
||||
// Zoom in centered on cursor
|
||||
if (min < -1.0 || max > 1.0) {
|
||||
min = -1.0;
|
||||
max = 1.0;
|
||||
}
|
||||
else {
|
||||
// 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;
|
||||
const 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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (spectral) {
|
||||
pTrack->SetSpectrumBounds(min, max);
|
||||
if (partner)
|
||||
partner->SetSpectrumBounds(min, max);
|
||||
}
|
||||
else {
|
||||
pTrack->SetDisplayBounds(min, max);
|
||||
if (partner)
|
||||
partner->SetDisplayBounds(min, max);
|
||||
}
|
||||
|
||||
zoomEnd = zoomStart = 0;
|
||||
pProject->ModifyState(true);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
enum {
|
||||
OnZoomInVerticalID = 20000,
|
||||
OnZoomOutVerticalID,
|
||||
OnZoomFitVerticalID,
|
||||
|
||||
// Reserve an ample block of ids for waveform scale types
|
||||
OnFirstWaveformScaleID,
|
||||
OnLastWaveformScaleID = OnFirstWaveformScaleID + 9,
|
||||
|
||||
// Reserve an ample block of ids for spectrum scale types
|
||||
OnFirstSpectrumScaleID,
|
||||
OnLastSpectrumScaleID = OnFirstSpectrumScaleID + 19,
|
||||
};
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// Table class
|
||||
|
||||
class WaveTrackVRulerMenuTable : public PopupMenuTable
|
||||
{
|
||||
protected:
|
||||
WaveTrackVRulerMenuTable() {}
|
||||
|
||||
void InitMenu(Menu *pMenu, void *pUserData) override;
|
||||
|
||||
private:
|
||||
void DestroyMenu() override
|
||||
{
|
||||
mpData = nullptr;
|
||||
}
|
||||
|
||||
protected:
|
||||
InitMenuData *mpData {};
|
||||
|
||||
void OnZoomInVertical(wxCommandEvent&);
|
||||
void OnZoomOutVertical(wxCommandEvent&);
|
||||
void OnZoomFitVertical(wxCommandEvent&);
|
||||
};
|
||||
|
||||
void WaveTrackVRulerMenuTable::InitMenu(Menu *, void *pUserData)
|
||||
{
|
||||
mpData = static_cast<InitMenuData*>(pUserData);
|
||||
}
|
||||
|
||||
void WaveTrackVRulerMenuTable::OnZoomInVertical(wxCommandEvent &)
|
||||
{
|
||||
HandleWaveTrackVZoom
|
||||
(::GetActiveProject(), mpData->pTrack, false, false, mpData->rect, mpData->yy, mpData->yy, false);
|
||||
|
||||
using namespace RefreshCode;
|
||||
mpData->result = UpdateVRuler | RefreshAll;
|
||||
}
|
||||
|
||||
void WaveTrackVRulerMenuTable::OnZoomOutVertical(wxCommandEvent &)
|
||||
{
|
||||
HandleWaveTrackVZoom
|
||||
(::GetActiveProject(), mpData->pTrack, true, false, mpData->rect, mpData->yy, mpData->yy, false);
|
||||
|
||||
using namespace RefreshCode;
|
||||
mpData->result = UpdateVRuler | RefreshAll;
|
||||
}
|
||||
|
||||
void WaveTrackVRulerMenuTable::OnZoomFitVertical(wxCommandEvent &)
|
||||
{
|
||||
HandleWaveTrackVZoom
|
||||
(::GetActiveProject(), mpData->pTrack, true, true, mpData->rect, mpData->yy, mpData->yy, false);
|
||||
|
||||
using namespace RefreshCode;
|
||||
mpData->result = UpdateVRuler | RefreshAll;
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// Table class
|
||||
|
||||
class WaveformVRulerMenuTable : public WaveTrackVRulerMenuTable
|
||||
{
|
||||
WaveformVRulerMenuTable() : WaveTrackVRulerMenuTable() {}
|
||||
virtual ~WaveformVRulerMenuTable() {}
|
||||
DECLARE_POPUP_MENU(WaveformVRulerMenuTable);
|
||||
|
||||
public:
|
||||
static WaveformVRulerMenuTable &Instance();
|
||||
|
||||
private:
|
||||
virtual void InitMenu(Menu *pMenu, void *pUserData);
|
||||
|
||||
void OnWaveformScaleType(wxCommandEvent &evt);
|
||||
};
|
||||
|
||||
WaveformVRulerMenuTable &WaveformVRulerMenuTable::Instance()
|
||||
{
|
||||
static WaveformVRulerMenuTable instance;
|
||||
return instance;
|
||||
}
|
||||
|
||||
void WaveformVRulerMenuTable::InitMenu(Menu *pMenu, void *pUserData)
|
||||
{
|
||||
WaveTrackVRulerMenuTable::InitMenu(pMenu, pUserData);
|
||||
|
||||
WaveTrack *const wt = mpData->pTrack;
|
||||
const int id =
|
||||
OnFirstWaveformScaleID + (int)(wt->GetWaveformSettings().scaleType);
|
||||
pMenu->Check(id, true);
|
||||
}
|
||||
|
||||
BEGIN_POPUP_MENU(WaveformVRulerMenuTable)
|
||||
|
||||
{
|
||||
const wxArrayString & names = WaveformSettings::GetScaleNames();
|
||||
for (int ii = 0, nn = names.size(); ii < nn; ++ii) {
|
||||
POPUP_MENU_RADIO_ITEM(OnFirstWaveformScaleID + ii, names[ii],
|
||||
OnWaveformScaleType);
|
||||
}
|
||||
}
|
||||
|
||||
POPUP_MENU_SEPARATOR()
|
||||
POPUP_MENU_ITEM(OnZoomInVerticalID, _("Zoom In\tLeft-Click/Left-Drag"), OnZoomInVertical)
|
||||
POPUP_MENU_ITEM(OnZoomOutVerticalID, _("Zoom Out\tShift-Left-Click"), OnZoomOutVertical)
|
||||
POPUP_MENU_ITEM(OnZoomFitVerticalID, _("Zoom to Fit\tShift-Right-Click"), OnZoomFitVertical)
|
||||
END_POPUP_MENU()
|
||||
|
||||
void WaveformVRulerMenuTable::OnWaveformScaleType(wxCommandEvent &evt)
|
||||
{
|
||||
WaveTrack *const wt = mpData->pTrack;
|
||||
// Assume linked track is wave or null
|
||||
const auto partner = static_cast<WaveTrack*>(wt->GetLink());
|
||||
const WaveformSettings::ScaleType newScaleType =
|
||||
WaveformSettings::ScaleType(
|
||||
std::max(0,
|
||||
std::min((int)(WaveformSettings::stNumScaleTypes) - 1,
|
||||
evt.GetId() - OnFirstWaveformScaleID
|
||||
)));
|
||||
if (wt->GetWaveformSettings().scaleType != newScaleType) {
|
||||
wt->GetIndependentWaveformSettings().scaleType = newScaleType;
|
||||
if (partner)
|
||||
partner->GetIndependentWaveformSettings().scaleType = newScaleType;
|
||||
|
||||
::GetActiveProject()->ModifyState(true);
|
||||
|
||||
using namespace RefreshCode;
|
||||
mpData->result = UpdateVRuler | RefreshAll;
|
||||
}
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// Table class
|
||||
|
||||
class SpectrumVRulerMenuTable : public WaveTrackVRulerMenuTable
|
||||
{
|
||||
SpectrumVRulerMenuTable() : WaveTrackVRulerMenuTable() {}
|
||||
virtual ~SpectrumVRulerMenuTable() {}
|
||||
DECLARE_POPUP_MENU(SpectrumVRulerMenuTable);
|
||||
|
||||
public:
|
||||
static SpectrumVRulerMenuTable &Instance();
|
||||
|
||||
private:
|
||||
void InitMenu(Menu *pMenu, void *pUserData);
|
||||
|
||||
void OnSpectrumScaleType(wxCommandEvent &evt);
|
||||
};
|
||||
|
||||
SpectrumVRulerMenuTable &SpectrumVRulerMenuTable::Instance()
|
||||
{
|
||||
static SpectrumVRulerMenuTable instance;
|
||||
return instance;
|
||||
}
|
||||
|
||||
void SpectrumVRulerMenuTable::InitMenu(Menu *pMenu, void *pUserData)
|
||||
{
|
||||
WaveTrackVRulerMenuTable::InitMenu(pMenu, pUserData);
|
||||
|
||||
WaveTrack *const wt = mpData->pTrack;
|
||||
const int id =
|
||||
OnFirstSpectrumScaleID + (int)(wt->GetSpectrogramSettings().scaleType);
|
||||
pMenu->Check(id, true);
|
||||
}
|
||||
|
||||
BEGIN_POPUP_MENU(SpectrumVRulerMenuTable)
|
||||
|
||||
{
|
||||
const wxArrayString & names = SpectrogramSettings::GetScaleNames();
|
||||
for (int ii = 0, nn = names.size(); ii < nn; ++ii) {
|
||||
POPUP_MENU_RADIO_ITEM(OnFirstSpectrumScaleID + ii, names[ii],
|
||||
OnSpectrumScaleType);
|
||||
}
|
||||
}
|
||||
|
||||
POPUP_MENU_SEPARATOR()
|
||||
POPUP_MENU_ITEM(OnZoomInVerticalID, _("Zoom In\tLeft-Click/Left-Drag"), OnZoomInVertical)
|
||||
POPUP_MENU_ITEM(OnZoomOutVerticalID, _("Zoom Out\tShift-Left-Click"), OnZoomOutVertical)
|
||||
POPUP_MENU_ITEM(OnZoomFitVerticalID, _("Zoom to Fit\tShift-Right-Click"), OnZoomFitVertical)
|
||||
END_POPUP_MENU()
|
||||
|
||||
void SpectrumVRulerMenuTable::OnSpectrumScaleType(wxCommandEvent &evt)
|
||||
{
|
||||
WaveTrack *const wt = mpData->pTrack;
|
||||
// Assume linked track is wave or null
|
||||
const auto partner = static_cast<WaveTrack*>(wt->GetLink());
|
||||
const SpectrogramSettings::ScaleType newScaleType =
|
||||
SpectrogramSettings::ScaleType(
|
||||
std::max(0,
|
||||
std::min((int)(SpectrogramSettings::stNumScaleTypes) - 1,
|
||||
evt.GetId() - OnFirstSpectrumScaleID
|
||||
)));
|
||||
if (wt->GetSpectrogramSettings().scaleType != newScaleType) {
|
||||
wt->GetIndependentSpectrogramSettings().scaleType = newScaleType;
|
||||
if (partner)
|
||||
partner->GetIndependentSpectrogramSettings().scaleType = newScaleType;
|
||||
|
||||
::GetActiveProject()->ModifyState(true);
|
||||
|
||||
using namespace RefreshCode;
|
||||
mpData->result = UpdateVRuler | RefreshAll;
|
||||
}
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
class WaveTrackVZoomHandle : public UIHandle
|
||||
{
|
||||
WaveTrackVZoomHandle();
|
||||
WaveTrackVZoomHandle(const WaveTrackVZoomHandle&);
|
||||
WaveTrackVZoomHandle &operator=(const WaveTrackVZoomHandle&);
|
||||
static WaveTrackVZoomHandle& Instance();
|
||||
static HitTestPreview HitPreview(const wxMouseEvent &event);
|
||||
|
||||
public:
|
||||
static HitTestResult HitTest(const wxMouseEvent &event);
|
||||
|
||||
virtual ~WaveTrackVZoomHandle();
|
||||
|
||||
virtual Result Click
|
||||
(const TrackPanelMouseEvent &event, AudacityProject *pProject);
|
||||
|
||||
virtual Result Drag
|
||||
(const TrackPanelMouseEvent &event, AudacityProject *pProject);
|
||||
|
||||
virtual HitTestPreview Preview
|
||||
(const TrackPanelMouseEvent &event, const AudacityProject *pProject);
|
||||
|
||||
virtual Result Release
|
||||
(const TrackPanelMouseEvent &event, AudacityProject *pProject,
|
||||
wxWindow *pParent);
|
||||
|
||||
virtual Result Cancel(AudacityProject *pProject);
|
||||
|
||||
virtual void DrawExtras
|
||||
(DrawingPass pass,
|
||||
wxDC * dc, const wxRegion &updateRegion, const wxRect &panelRect);
|
||||
|
||||
void OnProjectChange(AudacityProject *pProject) override;
|
||||
|
||||
private:
|
||||
WaveTrack *mpTrack{};
|
||||
|
||||
int mZoomStart{}, mZoomEnd{};
|
||||
wxRect mRect{};
|
||||
};
|
||||
|
||||
WaveTrackVZoomHandle::WaveTrackVZoomHandle()
|
||||
{
|
||||
}
|
||||
|
||||
WaveTrackVZoomHandle &WaveTrackVZoomHandle::Instance()
|
||||
{
|
||||
static WaveTrackVZoomHandle instance;
|
||||
return instance;
|
||||
}
|
||||
|
||||
HitTestPreview WaveTrackVZoomHandle::HitPreview(const wxMouseEvent &event)
|
||||
{
|
||||
static auto zoomInCursor =
|
||||
::MakeCursor(wxCURSOR_MAGNIFIER, ZoomInCursorXpm, 19, 15);
|
||||
static auto zoomOutCursor =
|
||||
::MakeCursor(wxCURSOR_MAGNIFIER, ZoomOutCursorXpm, 19, 15);
|
||||
return {
|
||||
_("Click to vertically zoom in. Shift-click to zoom out. Drag to specify a zoom region."),
|
||||
(event.ShiftDown() ? &*zoomOutCursor : &*zoomInCursor)
|
||||
};
|
||||
}
|
||||
|
||||
HitTestResult WaveTrackVZoomHandle::HitTest(const wxMouseEvent &event)
|
||||
{
|
||||
return { HitPreview(event), &Instance() };
|
||||
}
|
||||
|
||||
WaveTrackVZoomHandle::~WaveTrackVZoomHandle()
|
||||
{
|
||||
}
|
||||
|
||||
UIHandle::Result WaveTrackVZoomHandle::Click
|
||||
(const TrackPanelMouseEvent &evt, AudacityProject *)
|
||||
{
|
||||
mpTrack = static_cast<WaveTrack*>(
|
||||
static_cast<WaveTrackVRulerControls*>(evt.pCell)->GetTrack()
|
||||
);
|
||||
mRect = evt.rect;
|
||||
|
||||
const wxMouseEvent &event = evt.event;
|
||||
mZoomStart = event.m_y;
|
||||
mZoomEnd = event.m_y;
|
||||
|
||||
return RefreshCode::RefreshNone;
|
||||
}
|
||||
|
||||
UIHandle::Result WaveTrackVZoomHandle::Drag
|
||||
(const TrackPanelMouseEvent &evt, AudacityProject *)
|
||||
{
|
||||
const wxMouseEvent &event = evt.event;
|
||||
mZoomEnd = event.m_y;
|
||||
using namespace RefreshCode;
|
||||
if (IsDragZooming(mZoomStart, mZoomEnd))
|
||||
return RefreshAll;
|
||||
return RefreshNone;
|
||||
}
|
||||
|
||||
HitTestPreview WaveTrackVZoomHandle::Preview
|
||||
(const TrackPanelMouseEvent &evt, const AudacityProject *)
|
||||
{
|
||||
return HitPreview(evt.event);
|
||||
}
|
||||
|
||||
UIHandle::Result WaveTrackVZoomHandle::Release
|
||||
(const TrackPanelMouseEvent &evt, AudacityProject *pProject,
|
||||
wxWindow *pParent)
|
||||
{
|
||||
using namespace RefreshCode;
|
||||
if (!mpTrack)
|
||||
return RefreshNone;
|
||||
|
||||
const wxMouseEvent &event = evt.event;
|
||||
const bool shiftDown = event.ShiftDown();
|
||||
const bool rightUp = event.RightUp();
|
||||
|
||||
// Popup menu... disabled
|
||||
if (false &&
|
||||
rightUp &&
|
||||
!(event.ShiftDown() || event.CmdDown()))
|
||||
{
|
||||
InitMenuData data {
|
||||
mpTrack, mRect, RefreshCode::RefreshNone, event.m_y
|
||||
};
|
||||
|
||||
PopupMenuTable *const pTable =
|
||||
(mpTrack->GetDisplay() == WaveTrack::Spectrum)
|
||||
? (PopupMenuTable *) &SpectrumVRulerMenuTable::Instance()
|
||||
: (PopupMenuTable *) &WaveformVRulerMenuTable::Instance();
|
||||
std::unique_ptr<PopupMenuTable::Menu>
|
||||
pMenu(PopupMenuTable::BuildMenu(pParent, pTable, &data));
|
||||
|
||||
pParent->PopupMenu(pMenu.get(), event.m_x, event.m_y);
|
||||
|
||||
return data.result;
|
||||
}
|
||||
else
|
||||
HandleWaveTrackVZoom(pProject, mpTrack, shiftDown, rightUp,
|
||||
mRect, mZoomStart, mZoomEnd, false);
|
||||
|
||||
return UpdateVRuler | RefreshAll;
|
||||
}
|
||||
|
||||
UIHandle::Result WaveTrackVZoomHandle::Cancel(AudacityProject*)
|
||||
{
|
||||
// Cancel is implemented! And there is no initial state to restore,
|
||||
// so just return a code.
|
||||
return RefreshCode::RefreshAll;
|
||||
}
|
||||
|
||||
void WaveTrackVZoomHandle::DrawExtras
|
||||
(DrawingPass pass, wxDC * dc, const wxRegion &, const wxRect &panelRect)
|
||||
{
|
||||
if ( pass == UIHandle::Cells &&
|
||||
IsDragZooming( mZoomStart, mZoomEnd ) )
|
||||
TrackVRulerControls::DrawZooming
|
||||
( dc, mRect, panelRect, mZoomStart, mZoomEnd );
|
||||
}
|
||||
|
||||
void WaveTrackVZoomHandle::OnProjectChange(AudacityProject *pProject)
|
||||
{
|
||||
if (! pProject->GetTracks()->Contains(mpTrack)) {
|
||||
mpTrack = nullptr;
|
||||
mRect = {};
|
||||
}
|
||||
|
||||
UIHandle::OnProjectChange(pProject);
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
WaveTrackVRulerControls::WaveTrackVRulerControls()
|
||||
: TrackVRulerControls()
|
||||
{
|
||||
|
@ -28,8 +672,140 @@ WaveTrackVRulerControls::~WaveTrackVRulerControls()
|
|||
}
|
||||
|
||||
HitTestResult WaveTrackVRulerControls::HitTest
|
||||
(const TrackPanelMouseEvent &,
|
||||
(const TrackPanelMouseEvent &evt,
|
||||
const AudacityProject *)
|
||||
{
|
||||
return {};
|
||||
return WaveTrackVZoomHandle::HitTest(evt.event);
|
||||
}
|
||||
|
||||
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);
|
||||
|
||||
Track *const pTrack = GetTrack();
|
||||
wxASSERT(pTrack->GetKind() == Track::Wave);
|
||||
auto steps = evt.steps;
|
||||
|
||||
WaveTrack *const wt = static_cast<WaveTrack*>(pTrack);
|
||||
// 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;
|
||||
HandleWaveTrackVZoom(
|
||||
pProject, wt, false, (steps < 0),
|
||||
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;
|
||||
}
|
||||
|
|
|
@ -26,6 +26,10 @@ public:
|
|||
HitTestResult HitTest
|
||||
(const TrackPanelMouseEvent &event,
|
||||
const AudacityProject *) override;
|
||||
|
||||
unsigned HandleWheelRotation
|
||||
(const TrackPanelMouseEvent &event,
|
||||
AudacityProject *pProject) override;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
|
|
@ -12,6 +12,8 @@ Paul Licameli split from TrackPanel.cpp
|
|||
#include "../../HitTestResult.h"
|
||||
#include "TrackVRulerControls.h"
|
||||
|
||||
#include "../../TrackPanel.h"
|
||||
|
||||
#include <wx/cursor.h>
|
||||
#include <wx/translation.h>
|
||||
|
||||
|
@ -30,4 +32,26 @@ HitTestResult TrackVRulerControls::HitTest
|
|||
// Use a space for the tip, otherwise we get the default message.
|
||||
static wxCursor arrowCursor{ wxCURSOR_ARROW };
|
||||
return { { _(" "), &arrowCursor }, nullptr };
|
||||
}
|
||||
|
||||
void TrackVRulerControls::DrawZooming
|
||||
( wxDC *dc, const wxRect &cellRect, const wxRect &panelRect,
|
||||
int zoomStart, int zoomEnd )
|
||||
{
|
||||
// Draw a dashed rectangle, its right side disappearing in the black right
|
||||
// border of the track area, which is not part of this cell but right of it.
|
||||
wxRect rect;
|
||||
|
||||
dc->SetBrush(*wxTRANSPARENT_BRUSH);
|
||||
dc->SetPen(*wxBLACK_DASHED_PEN);
|
||||
|
||||
rect.y = std::min( zoomStart, zoomEnd);
|
||||
rect.height = 1 + abs( zoomEnd - zoomStart);
|
||||
|
||||
rect.x = cellRect.x;
|
||||
// TODO: Don't use the constant kRightMargin, but somehow discover the
|
||||
// neighboring track rectangle
|
||||
rect.SetRight(panelRect.GetWidth() - kRightMargin);
|
||||
|
||||
dc->DrawRectangle(rect);
|
||||
}
|
|
@ -14,6 +14,7 @@ Paul Licameli split from TrackPanel.cpp
|
|||
#include "CommonTrackPanelCell.h"
|
||||
|
||||
class Track;
|
||||
class wxDC;
|
||||
|
||||
class TrackVRulerControls /* not final */ : public CommonTrackPanelCell
|
||||
{
|
||||
|
@ -29,6 +30,10 @@ public:
|
|||
(const TrackPanelMouseEvent &event,
|
||||
const AudacityProject *pProject) override;
|
||||
|
||||
static void DrawZooming
|
||||
( wxDC *dc, const wxRect &cellRect, const wxRect &panelRect,
|
||||
int zoomStart, int zoomEnd);
|
||||
|
||||
protected:
|
||||
|
||||
Track *FindTrack() override;
|
||||
|
|
Loading…
Reference in New Issue
Block a user