mirror of
https://github.com/cookiengineer/audacity
synced 2025-11-14 17:14:07 +01:00
Move some handle and cell classes into their own files
This commit is contained in:
@@ -0,0 +1,98 @@
|
||||
/**********************************************************************
|
||||
|
||||
Audacity: A Digital Audio Editor
|
||||
|
||||
NoteTrackButtonHandle.cpp
|
||||
|
||||
Paul Licameli split from TrackPanel.cpp
|
||||
|
||||
**********************************************************************/
|
||||
|
||||
#include "../../../../Audacity.h"
|
||||
#include "NoteTrackButtonHandle.h"
|
||||
|
||||
#include "../../../../HitTestResult.h"
|
||||
#include "../../../../TrackPanelMouseEvent.h"
|
||||
#include "../../../../NoteTrack.h"
|
||||
#include "../../../../Project.h"
|
||||
#include "../../../../RefreshCode.h"
|
||||
#include "../../../../TrackPanel.h"
|
||||
|
||||
NoteTrackButtonHandle::NoteTrackButtonHandle()
|
||||
{
|
||||
}
|
||||
|
||||
NoteTrackButtonHandle::~NoteTrackButtonHandle()
|
||||
{
|
||||
}
|
||||
|
||||
NoteTrackButtonHandle &NoteTrackButtonHandle::Instance()
|
||||
{
|
||||
static NoteTrackButtonHandle instance;
|
||||
return instance;
|
||||
}
|
||||
|
||||
HitTestResult NoteTrackButtonHandle::HitTest
|
||||
(const wxMouseState &state, const wxRect &rect,
|
||||
const std::shared_ptr<NoteTrack> &pTrack)
|
||||
{
|
||||
wxRect midiRect;
|
||||
TrackInfo::GetMidiControlsRect(rect, midiRect);
|
||||
if ( TrackInfo::HideTopItem( rect, midiRect ) )
|
||||
return {};
|
||||
if (pTrack->GetKind() == Track::Note &&
|
||||
midiRect.Contains(state.m_x, state.m_y)) {
|
||||
Instance().mpTrack = pTrack;
|
||||
Instance().mRect = midiRect;
|
||||
return {
|
||||
HitTestPreview(),
|
||||
&Instance()
|
||||
};
|
||||
}
|
||||
else
|
||||
return {};
|
||||
}
|
||||
|
||||
UIHandle::Result NoteTrackButtonHandle::Click
|
||||
(const TrackPanelMouseEvent &, AudacityProject *)
|
||||
{
|
||||
return RefreshCode::RefreshNone;
|
||||
}
|
||||
|
||||
UIHandle::Result NoteTrackButtonHandle::Drag
|
||||
(const TrackPanelMouseEvent &, AudacityProject *)
|
||||
{
|
||||
return RefreshCode::RefreshNone;
|
||||
}
|
||||
|
||||
HitTestPreview NoteTrackButtonHandle::Preview
|
||||
(const TrackPanelMouseEvent &, const AudacityProject *)
|
||||
{
|
||||
// No special message or cursor
|
||||
return {};
|
||||
}
|
||||
|
||||
UIHandle::Result NoteTrackButtonHandle::Release
|
||||
(const TrackPanelMouseEvent &evt, AudacityProject *pProject, wxWindow *)
|
||||
{
|
||||
using namespace RefreshCode;
|
||||
|
||||
auto pTrack = pProject->GetTracks()->Lock(mpTrack);
|
||||
if (!pTrack)
|
||||
return Cancelled;
|
||||
|
||||
const wxMouseEvent &event = evt.event;
|
||||
if (pTrack->LabelClick(mRect, event.m_x, event.m_y,
|
||||
event.Button(wxMOUSE_BTN_RIGHT))) {
|
||||
// No undo items needed??
|
||||
pProject->ModifyState(false);
|
||||
return RefreshAll;
|
||||
}
|
||||
return RefreshNone;
|
||||
}
|
||||
|
||||
UIHandle::Result NoteTrackButtonHandle::Cancel(AudacityProject *)
|
||||
{
|
||||
return RefreshCode::RefreshNone;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,58 @@
|
||||
/**********************************************************************
|
||||
|
||||
Audacity: A Digital Audio Editor
|
||||
|
||||
NoteTrackButtonHandle.h
|
||||
|
||||
Paul Licameli split from TrackPanel.cpp
|
||||
|
||||
**********************************************************************/
|
||||
|
||||
#ifndef __AUDACITY_NOTE_TRACK_BUTTON_HANDLE__
|
||||
#define __AUDACITY_NOTE_TRACK_BUTTON_HANDLE__
|
||||
|
||||
class wxMouseState;
|
||||
class NoteTrack;
|
||||
struct HitTestResult;
|
||||
|
||||
#include <wx/gdicmn.h>
|
||||
#include "../../../../MemoryX.h"
|
||||
#include "../../../../UIHandle.h"
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// TODO: do appearance changes as in ButtonHandle, or even, inherit from that
|
||||
class NoteTrackButtonHandle : public UIHandle
|
||||
{
|
||||
NoteTrackButtonHandle(const NoteTrackButtonHandle&);
|
||||
NoteTrackButtonHandle &operator=(const NoteTrackButtonHandle&);
|
||||
NoteTrackButtonHandle();
|
||||
virtual ~NoteTrackButtonHandle();
|
||||
static NoteTrackButtonHandle& Instance();
|
||||
|
||||
public:
|
||||
static HitTestResult HitTest
|
||||
(const wxMouseState &state, const wxRect &rect,
|
||||
const std::shared_ptr<NoteTrack> &pTrack);
|
||||
|
||||
protected:
|
||||
Result Click
|
||||
(const TrackPanelMouseEvent &event, AudacityProject *pProject) override;
|
||||
|
||||
Result Drag
|
||||
(const TrackPanelMouseEvent &event, AudacityProject *pProject) override;
|
||||
|
||||
HitTestPreview Preview
|
||||
(const TrackPanelMouseEvent &event, const AudacityProject *pProject)
|
||||
override;
|
||||
|
||||
Result Release
|
||||
(const TrackPanelMouseEvent &event, AudacityProject *pProject,
|
||||
wxWindow *pParent) override;
|
||||
|
||||
Result Cancel(AudacityProject *pProject) override;
|
||||
|
||||
std::weak_ptr<NoteTrack> mpTrack;
|
||||
wxRect mRect{};
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -13,132 +13,17 @@ Paul Licameli split from TrackPanel.cpp
|
||||
#ifdef USE_MIDI
|
||||
|
||||
#include "NoteTrackControls.h"
|
||||
#include "NoteTrackButtonHandle.h"
|
||||
|
||||
#include "../../ui/PlayableTrackButtonHandles.h"
|
||||
#include "NoteTrackSliderHandles.h"
|
||||
|
||||
#include "../../../../HitTestResult.h"
|
||||
#include "../../../../Track.h"
|
||||
#include "../../../../TrackPanelMouseEvent.h"
|
||||
#include "../../../../NoteTrack.h"
|
||||
#include "../../../../widgets/PopupMenuTable.h"
|
||||
#include "../../../../Project.h"
|
||||
#include "../../../../RefreshCode.h"
|
||||
#include "../../../../TrackPanel.h"
|
||||
#include "../../../../TrackPanelMouseEvent.h"
|
||||
#include "../../../../UIHandle.h"
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// TODO: do appearance changes as in ButtonHandle, or even, inherit from that
|
||||
class NoteTrackClickHandle : public UIHandle
|
||||
{
|
||||
NoteTrackClickHandle(const NoteTrackClickHandle&);
|
||||
NoteTrackClickHandle &operator=(const NoteTrackClickHandle&);
|
||||
NoteTrackClickHandle();
|
||||
virtual ~NoteTrackClickHandle();
|
||||
static NoteTrackClickHandle& Instance();
|
||||
|
||||
public:
|
||||
static HitTestResult HitTest
|
||||
(const wxMouseEvent &event, const wxRect &rect,
|
||||
const std::shared_ptr<NoteTrack> &pTrack);
|
||||
|
||||
protected:
|
||||
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);
|
||||
|
||||
std::weak_ptr<NoteTrack> mpTrack;
|
||||
wxRect mRect{};
|
||||
};
|
||||
|
||||
NoteTrackClickHandle::NoteTrackClickHandle()
|
||||
{
|
||||
}
|
||||
|
||||
NoteTrackClickHandle::~NoteTrackClickHandle()
|
||||
{
|
||||
}
|
||||
|
||||
NoteTrackClickHandle &NoteTrackClickHandle::Instance()
|
||||
{
|
||||
static NoteTrackClickHandle instance;
|
||||
return instance;
|
||||
}
|
||||
|
||||
HitTestResult NoteTrackClickHandle::HitTest
|
||||
(const wxMouseEvent &event, const wxRect &rect,
|
||||
const std::shared_ptr<NoteTrack> &pTrack)
|
||||
{
|
||||
wxRect midiRect;
|
||||
TrackInfo::GetMidiControlsRect(rect, midiRect);
|
||||
if ( TrackInfo::HideTopItem( rect, midiRect ) )
|
||||
return {};
|
||||
if (pTrack->GetKind() == Track::Note &&
|
||||
midiRect.Contains(event.m_x, event.m_y)) {
|
||||
Instance().mpTrack = pTrack;
|
||||
Instance().mRect = midiRect;
|
||||
return {
|
||||
HitTestPreview(),
|
||||
&Instance()
|
||||
};
|
||||
}
|
||||
else
|
||||
return {};
|
||||
}
|
||||
|
||||
UIHandle::Result NoteTrackClickHandle::Click
|
||||
(const TrackPanelMouseEvent &, AudacityProject *)
|
||||
{
|
||||
return RefreshCode::RefreshNone;
|
||||
}
|
||||
|
||||
UIHandle::Result NoteTrackClickHandle::Drag
|
||||
(const TrackPanelMouseEvent &, AudacityProject *)
|
||||
{
|
||||
return RefreshCode::RefreshNone;
|
||||
}
|
||||
|
||||
HitTestPreview NoteTrackClickHandle::Preview
|
||||
(const TrackPanelMouseEvent &, const AudacityProject *)
|
||||
{
|
||||
// No special message or cursor
|
||||
return {};
|
||||
}
|
||||
|
||||
UIHandle::Result NoteTrackClickHandle::Release
|
||||
(const TrackPanelMouseEvent &evt, AudacityProject *pProject, wxWindow *)
|
||||
{
|
||||
using namespace RefreshCode;
|
||||
|
||||
auto pTrack = pProject->GetTracks()->Lock(mpTrack);
|
||||
if (!pTrack)
|
||||
return Cancelled;
|
||||
|
||||
const wxMouseEvent &event = evt.event;
|
||||
if (pTrack->LabelClick(mRect, event.m_x, event.m_y,
|
||||
event.Button(wxMOUSE_BTN_RIGHT))) {
|
||||
// No undo items needed??
|
||||
pProject->ModifyState(false);
|
||||
return RefreshAll;
|
||||
}
|
||||
return RefreshNone;
|
||||
}
|
||||
|
||||
UIHandle::Result NoteTrackClickHandle::Cancel(AudacityProject *)
|
||||
{
|
||||
return RefreshCode::RefreshNone;
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
NoteTrackControls::~NoteTrackControls()
|
||||
@@ -169,7 +54,7 @@ HitTestResult NoteTrackControls::HitTest
|
||||
VelocitySliderHandle::HitTest(event, rect, pProject, track)).handle)
|
||||
return result;
|
||||
if (NULL != (result =
|
||||
NoteTrackClickHandle::HitTest(event, rect, track)).handle)
|
||||
NoteTrackButtonHandle::HitTest(event, rect, track)).handle)
|
||||
return result;
|
||||
#endif
|
||||
}
|
||||
|
||||
@@ -13,195 +13,14 @@ Paul Licameli split from TrackPanel.cpp
|
||||
#ifdef USE_MIDI
|
||||
|
||||
#include "NoteTrackVRulerControls.h"
|
||||
#include "NoteTrackVZoomHandle.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);
|
||||
|
||||
private:
|
||||
std::weak_ptr<NoteTrack> mpTrack;
|
||||
|
||||
int mZoomStart, mZoomEnd;
|
||||
wxRect mRect;
|
||||
};
|
||||
|
||||
NoteTrackVZoomHandle::NoteTrackVZoomHandle()
|
||||
: 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 vertically zoom in. Shift-click to zoom out. Drag to specify a 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 = std::static_pointer_cast<NoteTrack>(
|
||||
static_cast<NoteTrackVRulerControls*>(evt.pCell.get())->FindTrack() );
|
||||
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)
|
||||
{
|
||||
using namespace RefreshCode;
|
||||
auto pTrack = pProject->GetTracks()->Lock(mpTrack);
|
||||
if (!pTrack)
|
||||
return Cancelled;
|
||||
|
||||
const wxMouseEvent &event = evt.event;
|
||||
mZoomEnd = event.m_y;
|
||||
if (IsDragZooming(mZoomStart, mZoomEnd)) {
|
||||
// changed Note track to work like audio track
|
||||
// pTrack->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;
|
||||
auto pTrack = pProject->GetTracks()->Lock(mpTrack);
|
||||
if (!pTrack)
|
||||
return RefreshNone;
|
||||
|
||||
const wxMouseEvent &event = evt.event;
|
||||
if (IsDragZooming(mZoomStart, mZoomEnd)) {
|
||||
pTrack->ZoomTo(evt.rect, mZoomStart, mZoomEnd);
|
||||
}
|
||||
else if (event.ShiftDown() || event.RightUp()) {
|
||||
if (event.ShiftDown() && event.RightUp()) {
|
||||
// Zoom out completely
|
||||
pTrack->SetBottomNote(0);
|
||||
auto octavePadding = 2 * 10; // 10 octaves times 2 single-pixel seperations per pixel
|
||||
auto availableHeight = evt.rect.height - octavePadding;
|
||||
auto numNotes = 128;
|
||||
auto spacePerNote = availableHeight / numNotes;
|
||||
pTrack->SetPitchHeight(std::max(spacePerNote, 1));
|
||||
} else {
|
||||
// Zoom out
|
||||
pTrack->ZoomOut(evt.rect, mZoomEnd);
|
||||
}
|
||||
}
|
||||
else {
|
||||
pTrack->ZoomIn(evt.rect, mZoomEnd);
|
||||
}
|
||||
|
||||
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 (!mpTrack.lock()) //? TrackList::Lock()
|
||||
return;
|
||||
|
||||
if ( pass == UIHandle::Cells &&
|
||||
IsDragZooming( mZoomStart, mZoomEnd ) )
|
||||
TrackVRulerControls::DrawZooming
|
||||
( dc, mRect, panelRect, mZoomStart, mZoomEnd );
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
NoteTrackVRulerControls::~NoteTrackVRulerControls()
|
||||
|
||||
164
src/tracks/playabletrack/notetrack/ui/NoteTrackVZoomHandle.cpp
Normal file
164
src/tracks/playabletrack/notetrack/ui/NoteTrackVZoomHandle.cpp
Normal file
@@ -0,0 +1,164 @@
|
||||
/**********************************************************************
|
||||
|
||||
Audacity: A Digital Audio Editor
|
||||
|
||||
NoteTrackVZoomHandle.cpp
|
||||
|
||||
Paul Licameli split from TrackPanel.cpp
|
||||
|
||||
**********************************************************************/
|
||||
|
||||
#include "../../../../Audacity.h"
|
||||
#include "NoteTrackVZoomHandle.h"
|
||||
#include "NoteTrackVRulerControls.h"
|
||||
|
||||
#include "../../../../HitTestResult.h"
|
||||
#include "../../../../NoteTrack.h"
|
||||
#include "../../../../Project.h"
|
||||
#include "../../../../RefreshCode.h"
|
||||
#include "../../../../TrackPanelMouseEvent.h"
|
||||
#include "../../../../../images/Cursors.h"
|
||||
|
||||
#include <wx/event.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);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
NoteTrackVZoomHandle::NoteTrackVZoomHandle()
|
||||
: mZoomStart(0), mZoomEnd(0), mRect()
|
||||
{
|
||||
}
|
||||
|
||||
NoteTrackVZoomHandle &NoteTrackVZoomHandle::Instance()
|
||||
{
|
||||
static NoteTrackVZoomHandle instance;
|
||||
return instance;
|
||||
}
|
||||
|
||||
HitTestPreview NoteTrackVZoomHandle::HitPreview(const wxMouseState &state)
|
||||
{
|
||||
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."),
|
||||
(state.ShiftDown() ? &*zoomOutCursor : &*zoomInCursor)
|
||||
};
|
||||
}
|
||||
|
||||
HitTestResult NoteTrackVZoomHandle::HitTest(const wxMouseState &state)
|
||||
{
|
||||
return HitTestResult(HitPreview(state), &Instance());
|
||||
}
|
||||
|
||||
NoteTrackVZoomHandle::~NoteTrackVZoomHandle()
|
||||
{
|
||||
}
|
||||
|
||||
UIHandle::Result NoteTrackVZoomHandle::Click
|
||||
(const TrackPanelMouseEvent &evt, AudacityProject *pProject)
|
||||
{
|
||||
mpTrack = std::static_pointer_cast<NoteTrack>(
|
||||
static_cast<NoteTrackVRulerControls*>(evt.pCell.get())->FindTrack() );
|
||||
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)
|
||||
{
|
||||
using namespace RefreshCode;
|
||||
auto pTrack = pProject->GetTracks()->Lock(mpTrack);
|
||||
if (!pTrack)
|
||||
return Cancelled;
|
||||
|
||||
const wxMouseEvent &event = evt.event;
|
||||
mZoomEnd = event.m_y;
|
||||
if (IsDragZooming(mZoomStart, mZoomEnd)) {
|
||||
// changed Note track to work like audio track
|
||||
// pTrack->VScroll(mZoomStart, mZoomEnd);
|
||||
return RefreshAll;
|
||||
}
|
||||
return RefreshNone;
|
||||
}
|
||||
|
||||
HitTestPreview NoteTrackVZoomHandle::Preview
|
||||
(const TrackPanelMouseEvent &evt, const AudacityProject *)
|
||||
{
|
||||
return HitPreview(evt.event);
|
||||
}
|
||||
|
||||
UIHandle::Result NoteTrackVZoomHandle::Release
|
||||
(const TrackPanelMouseEvent &evt, AudacityProject *pProject,
|
||||
wxWindow *pParent)
|
||||
{
|
||||
using namespace RefreshCode;
|
||||
auto pTrack = pProject->GetTracks()->Lock(mpTrack);
|
||||
if (!pTrack)
|
||||
return RefreshNone;
|
||||
|
||||
const wxMouseEvent &event = evt.event;
|
||||
if (IsDragZooming(mZoomStart, mZoomEnd)) {
|
||||
pTrack->ZoomTo(evt.rect, mZoomStart, mZoomEnd);
|
||||
}
|
||||
else if (event.ShiftDown() || event.RightUp()) {
|
||||
if (event.ShiftDown() && event.RightUp()) {
|
||||
// Zoom out completely
|
||||
pTrack->SetBottomNote(0);
|
||||
auto octavePadding = 2 * 10; // 10 octaves times 2 single-pixel seperations per pixel
|
||||
auto availableHeight = evt.rect.height - octavePadding;
|
||||
auto numNotes = 128;
|
||||
auto spacePerNote = availableHeight / numNotes;
|
||||
pTrack->SetPitchHeight(std::max(spacePerNote, 1));
|
||||
} else {
|
||||
// Zoom out
|
||||
pTrack->ZoomOut(evt.rect, mZoomEnd);
|
||||
}
|
||||
}
|
||||
else {
|
||||
pTrack->ZoomIn(evt.rect, mZoomEnd);
|
||||
}
|
||||
|
||||
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 (!mpTrack.lock()) //? TrackList::Lock()
|
||||
return;
|
||||
|
||||
if ( pass == UIHandle::Cells &&
|
||||
IsDragZooming( mZoomStart, mZoomEnd ) )
|
||||
TrackVRulerControls::DrawZooming
|
||||
( dc, mRect, panelRect, mZoomStart, mZoomEnd );
|
||||
}
|
||||
63
src/tracks/playabletrack/notetrack/ui/NoteTrackVZoomHandle.h
Normal file
63
src/tracks/playabletrack/notetrack/ui/NoteTrackVZoomHandle.h
Normal file
@@ -0,0 +1,63 @@
|
||||
/**********************************************************************
|
||||
|
||||
Audacity: A Digital Audio Editor
|
||||
|
||||
NoteTrackVZoomHandle.h
|
||||
|
||||
Paul Licameli split from TrackPanel.cpp
|
||||
|
||||
**********************************************************************/
|
||||
|
||||
#ifndef __AUDACITY_NOTE_TRACK_VZOOM_HANDLE__
|
||||
#define __AUDACITY_NOTE_TRACK_VZOOM_HANDLE__
|
||||
|
||||
class wxMouseState;
|
||||
struct HitTestResult;
|
||||
class NoteTrack;
|
||||
|
||||
#include "../../../../MemoryX.h"
|
||||
#include "../../../../UIHandle.h"
|
||||
#include <wx/gdicmn.h>
|
||||
|
||||
class NoteTrackVZoomHandle : public UIHandle
|
||||
{
|
||||
NoteTrackVZoomHandle();
|
||||
NoteTrackVZoomHandle(const NoteTrackVZoomHandle&);
|
||||
NoteTrackVZoomHandle &operator=(const NoteTrackVZoomHandle&);
|
||||
static NoteTrackVZoomHandle& Instance();
|
||||
static HitTestPreview HitPreview(const wxMouseState &state);
|
||||
|
||||
public:
|
||||
static HitTestResult HitTest(const wxMouseState &state);
|
||||
|
||||
virtual ~NoteTrackVZoomHandle();
|
||||
|
||||
Result Click
|
||||
(const TrackPanelMouseEvent &event, AudacityProject *pProject) override;
|
||||
|
||||
Result Drag
|
||||
(const TrackPanelMouseEvent &event, AudacityProject *pProject) override;
|
||||
|
||||
HitTestPreview Preview
|
||||
(const TrackPanelMouseEvent &event, const AudacityProject *pProject)
|
||||
override;
|
||||
|
||||
Result Release
|
||||
(const TrackPanelMouseEvent &event, AudacityProject *pProject,
|
||||
wxWindow *pParent) override;
|
||||
|
||||
Result Cancel(AudacityProject *pProject) override;
|
||||
|
||||
void DrawExtras
|
||||
(DrawingPass pass,
|
||||
wxDC * dc, const wxRegion &updateRegion, const wxRect &panelRect)
|
||||
override;
|
||||
|
||||
private:
|
||||
std::weak_ptr<NoteTrack> mpTrack;
|
||||
|
||||
int mZoomStart, mZoomEnd;
|
||||
wxRect mRect;
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -10,8 +10,7 @@ Paul Licameli split from TrackPanel.cpp
|
||||
|
||||
#include "../../../../Audacity.h"
|
||||
#include "WaveTrackVRulerControls.h"
|
||||
|
||||
#include <algorithm>
|
||||
#include "WaveTrackVZoomHandle.h"
|
||||
|
||||
#include "../../../../HitTestResult.h"
|
||||
#include "../../../../NumberScale.h"
|
||||
@@ -20,636 +19,11 @@ Paul Licameli split from TrackPanel.cpp
|
||||
#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>
|
||||
#include <wx/event.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);
|
||||
|
||||
private:
|
||||
std::weak_ptr<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 = std::static_pointer_cast<WaveTrack>(
|
||||
static_cast<WaveTrackVRulerControls*>(evt.pCell.get())->FindTrack() );
|
||||
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 *pProject)
|
||||
{
|
||||
using namespace RefreshCode;
|
||||
auto pTrack = pProject->GetTracks()->Lock(mpTrack);
|
||||
if (!pTrack)
|
||||
return Cancelled;
|
||||
|
||||
const wxMouseEvent &event = evt.event;
|
||||
mZoomEnd = event.m_y;
|
||||
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;
|
||||
auto pTrack = pProject->GetTracks()->Lock(mpTrack);
|
||||
if (!pTrack)
|
||||
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 {
|
||||
pTrack.get(), mRect, RefreshCode::RefreshNone, event.m_y
|
||||
};
|
||||
|
||||
PopupMenuTable *const pTable =
|
||||
(pTrack->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, pTrack.get(), 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 (!mpTrack.lock()) // TrackList::Lock()?
|
||||
return;
|
||||
|
||||
if ( pass == UIHandle::Cells &&
|
||||
IsDragZooming( mZoomStart, mZoomEnd ) )
|
||||
TrackVRulerControls::DrawZooming
|
||||
( dc, mRect, panelRect, mZoomStart, mZoomEnd );
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
WaveTrackVRulerControls::~WaveTrackVRulerControls()
|
||||
{
|
||||
@@ -738,7 +112,7 @@ unsigned WaveTrackVRulerControls::HandleWheelRotation
|
||||
}
|
||||
else if (event.CmdDown() && !event.ShiftDown()) {
|
||||
const int yy = event.m_y;
|
||||
HandleWaveTrackVZoom(
|
||||
WaveTrackVZoomHandle::DoZoom(
|
||||
pProject, wt, false, (steps < 0),
|
||||
evt.rect, yy, yy, true);
|
||||
}
|
||||
|
||||
607
src/tracks/playabletrack/wavetrack/ui/WaveTrackVZoomHandle.cpp
Normal file
607
src/tracks/playabletrack/wavetrack/ui/WaveTrackVZoomHandle.cpp
Normal file
@@ -0,0 +1,607 @@
|
||||
/**********************************************************************
|
||||
|
||||
Audacity: A Digital Audio Editor
|
||||
|
||||
WaveTrackVZoomHandle.cpp
|
||||
|
||||
Paul Licameli split from TrackPanel.cpp
|
||||
|
||||
**********************************************************************/
|
||||
|
||||
#include "../../../../Audacity.h"
|
||||
#include "WaveTrackVZoomHandle.h"
|
||||
#include "WaveTrackVRulerControls.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"
|
||||
#include "../../../../widgets/PopupMenuTable.h"
|
||||
#include "../../../../../images/Cursors.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 WaveTrackVZoomHandle::DoZoom
|
||||
(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 &)
|
||||
{
|
||||
WaveTrackVZoomHandle::DoZoom
|
||||
(::GetActiveProject(), mpData->pTrack, false, false, mpData->rect, mpData->yy, mpData->yy, false);
|
||||
|
||||
using namespace RefreshCode;
|
||||
mpData->result = UpdateVRuler | RefreshAll;
|
||||
}
|
||||
|
||||
void WaveTrackVRulerMenuTable::OnZoomOutVertical(wxCommandEvent &)
|
||||
{
|
||||
WaveTrackVZoomHandle::DoZoom
|
||||
(::GetActiveProject(), mpData->pTrack, true, false, mpData->rect, mpData->yy, mpData->yy, false);
|
||||
|
||||
using namespace RefreshCode;
|
||||
mpData->result = UpdateVRuler | RefreshAll;
|
||||
}
|
||||
|
||||
void WaveTrackVRulerMenuTable::OnZoomFitVertical(wxCommandEvent &)
|
||||
{
|
||||
WaveTrackVZoomHandle::DoZoom
|
||||
(::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;
|
||||
}
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
WaveTrackVZoomHandle::WaveTrackVZoomHandle()
|
||||
{
|
||||
}
|
||||
|
||||
WaveTrackVZoomHandle &WaveTrackVZoomHandle::Instance()
|
||||
{
|
||||
static WaveTrackVZoomHandle instance;
|
||||
return instance;
|
||||
}
|
||||
|
||||
HitTestPreview WaveTrackVZoomHandle::HitPreview(const wxMouseState &state)
|
||||
{
|
||||
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."),
|
||||
(state.ShiftDown() ? &*zoomOutCursor : &*zoomInCursor)
|
||||
};
|
||||
}
|
||||
|
||||
HitTestResult WaveTrackVZoomHandle::HitTest(const wxMouseState &state)
|
||||
{
|
||||
return { HitPreview(state), &Instance() };
|
||||
}
|
||||
|
||||
WaveTrackVZoomHandle::~WaveTrackVZoomHandle()
|
||||
{
|
||||
}
|
||||
|
||||
UIHandle::Result WaveTrackVZoomHandle::Click
|
||||
(const TrackPanelMouseEvent &evt, AudacityProject *)
|
||||
{
|
||||
mpTrack = std::static_pointer_cast<WaveTrack>(
|
||||
static_cast<WaveTrackVRulerControls*>(evt.pCell.get())->FindTrack() );
|
||||
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 *pProject)
|
||||
{
|
||||
using namespace RefreshCode;
|
||||
auto pTrack = pProject->GetTracks()->Lock(mpTrack);
|
||||
if (!pTrack)
|
||||
return Cancelled;
|
||||
|
||||
const wxMouseEvent &event = evt.event;
|
||||
mZoomEnd = event.m_y;
|
||||
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;
|
||||
auto pTrack = pProject->GetTracks()->Lock(mpTrack);
|
||||
if (!pTrack)
|
||||
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 {
|
||||
pTrack.get(), mRect, RefreshCode::RefreshNone, event.m_y
|
||||
};
|
||||
|
||||
PopupMenuTable *const pTable =
|
||||
(pTrack->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
|
||||
DoZoom(pProject, pTrack.get(), 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 (!mpTrack.lock()) // TrackList::Lock()?
|
||||
return;
|
||||
|
||||
if ( pass == UIHandle::Cells &&
|
||||
IsDragZooming( mZoomStart, mZoomEnd ) )
|
||||
TrackVRulerControls::DrawZooming
|
||||
( dc, mRect, panelRect, mZoomStart, mZoomEnd );
|
||||
}
|
||||
|
||||
69
src/tracks/playabletrack/wavetrack/ui/WaveTrackVZoomHandle.h
Normal file
69
src/tracks/playabletrack/wavetrack/ui/WaveTrackVZoomHandle.h
Normal file
@@ -0,0 +1,69 @@
|
||||
/**********************************************************************
|
||||
|
||||
Audacity: A Digital Audio Editor
|
||||
|
||||
WaveTrackVZoomHandle.h
|
||||
|
||||
Paul Licameli split from TrackPanel.cpp
|
||||
|
||||
**********************************************************************/
|
||||
|
||||
#ifndef __AUDACITY_WAVE_TRACK_VZOOM_HANDLE__
|
||||
#define __AUDACITY_WAVE_TRACK_VZOOM_HANDLE__
|
||||
|
||||
class wxMouseState;
|
||||
class WaveTrack;
|
||||
#include <wx/gdicmn.h>
|
||||
#include "../../../../MemoryX.h"
|
||||
#include "../../../../UIHandle.h"
|
||||
|
||||
struct HitTestResult;
|
||||
|
||||
class WaveTrackVZoomHandle : public UIHandle
|
||||
{
|
||||
WaveTrackVZoomHandle();
|
||||
WaveTrackVZoomHandle(const WaveTrackVZoomHandle&);
|
||||
WaveTrackVZoomHandle &operator=(const WaveTrackVZoomHandle&);
|
||||
static WaveTrackVZoomHandle& Instance();
|
||||
static HitTestPreview HitPreview(const wxMouseState &state);
|
||||
|
||||
public:
|
||||
static HitTestResult HitTest(const wxMouseState &state);
|
||||
|
||||
static void DoZoom
|
||||
(AudacityProject *pProject,
|
||||
WaveTrack *pTrack, bool shiftDown, bool rightUp,
|
||||
const wxRect &rect, int zoomStart, int zoomEnd,
|
||||
bool fixedMousePoint);
|
||||
|
||||
virtual ~WaveTrackVZoomHandle();
|
||||
|
||||
Result Click
|
||||
(const TrackPanelMouseEvent &event, AudacityProject *pProject) override;
|
||||
|
||||
Result Drag
|
||||
(const TrackPanelMouseEvent &event, AudacityProject *pProject) override;
|
||||
|
||||
HitTestPreview Preview
|
||||
(const TrackPanelMouseEvent &event, const AudacityProject *pProject)
|
||||
override;
|
||||
|
||||
Result Release
|
||||
(const TrackPanelMouseEvent &event, AudacityProject *pProject,
|
||||
wxWindow *pParent) override;
|
||||
|
||||
Result Cancel(AudacityProject *pProject) override;
|
||||
|
||||
void DrawExtras
|
||||
(DrawingPass pass,
|
||||
wxDC * dc, const wxRegion &updateRegion, const wxRect &panelRect)
|
||||
override;
|
||||
|
||||
private:
|
||||
std::weak_ptr<WaveTrack> mpTrack;
|
||||
|
||||
int mZoomStart{}, mZoomEnd{};
|
||||
wxRect mRect{};
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -22,6 +22,7 @@ Paul Licameli split from TrackPanel.cpp
|
||||
#include "../playabletrack/wavetrack/ui/SampleHandle.h"
|
||||
#include "ZoomHandle.h"
|
||||
#include "TimeShiftHandle.h"
|
||||
#include "../../TrackPanelResizerCell.h"
|
||||
|
||||
HitTestResult Track::HitTest
|
||||
(const TrackPanelMouseEvent &event,
|
||||
|
||||
Reference in New Issue
Block a user