1
0
mirror of https://github.com/cookiengineer/audacity synced 2025-05-02 16:49:41 +02:00

Changed hit test priorities; message, cursor for text box mouse-over

This commit is contained in:
Paul Licameli 2017-06-27 08:34:51 -04:00
commit 1c0af82903
18 changed files with 237 additions and 276 deletions

View File

@ -121,9 +121,10 @@ class AUDACITY_DLL_API LabelTrack final : public Track
virtual ~ LabelTrack();
HitTestResult HitTest
HitTestResult DetailedHitTest
(const TrackPanelMouseEvent &event,
const AudacityProject *pProject) override;
const AudacityProject *pProject, int currentTool, bool bMultiTool)
override;
bool DoCaptureKey(wxKeyEvent &event);
unsigned CaptureKey

View File

@ -68,9 +68,10 @@ class AUDACITY_DLL_API NoteTrack final
NoteTrack(const std::shared_ptr<DirManager> &projDirManager);
virtual ~NoteTrack();
HitTestResult HitTest
HitTestResult DetailedHitTest
(const TrackPanelMouseEvent &event,
const AudacityProject *pProject) override;
const AudacityProject *pProject, int currentTool, bool bMultiTool)
override;
using Holder = std::unique_ptr<NoteTrack>;
Track::Holder Duplicate() const override;

View File

@ -49,9 +49,10 @@ class TimeTrack final : public Track {
void Silence(double t0, double t1) override;
void InsertSilence(double t, double len) override;
HitTestResult HitTest
HitTestResult DetailedHitTest
(const TrackPanelMouseEvent &event,
const AudacityProject *pProject) override;
const AudacityProject *pProject, int currentTool, bool bMultiTool)
override;
// Identifying the type of track
int GetKind() const override { return Time; }

View File

@ -108,7 +108,6 @@ class AUDACITY_DLL_API Track /* not final */
bool mMinimized;
public:
mutable wxSize vrulerSize;
// Given a bare pointer, find a shared_ptr. But this is not possible for
// a track not owned by any list, so the result can be null.
@ -131,11 +130,22 @@ class AUDACITY_DLL_API Track /* not final */
return {};
}
// An implementation is defined for call-through from subclasses, but
// the inherited method is still marked pure virtual
// Cause certain overriding tool modes (Zoom; future ones?) to behave
// uniformly in all tracks, disregarding track contents.
// Do not further override this...
HitTestResult HitTest
(const TrackPanelMouseEvent &, const AudacityProject *pProject)
override = 0;
final;
public:
// Rather override this for subclasses:
virtual HitTestResult DetailedHitTest
(const TrackPanelMouseEvent &,
const AudacityProject *pProject, int currentTool, bool bMultiTool)
= 0;
mutable wxSize vrulerSize;
// Return another, associated TrackPanelCell object that implements the
// drop-down, close and minimize buttons, etc.

View File

@ -103,9 +103,10 @@ class AUDACITY_DLL_API WaveTrack final : public PlayableTrack {
virtual ~WaveTrack();
HitTestResult HitTest
HitTestResult DetailedHitTest
(const TrackPanelMouseEvent &event,
const AudacityProject *pProject) override;
const AudacityProject *pProject, int currentTool, bool bMultiTool)
override;
double GetOffset() const override;
void SetOffset(double o) override;

View File

@ -21,12 +21,6 @@ LabelDefaultClickHandle::LabelDefaultClickHandle()
{
}
LabelDefaultClickHandle &LabelDefaultClickHandle::Instance()
{
static LabelDefaultClickHandle instance;
return instance;
}
LabelDefaultClickHandle::~LabelDefaultClickHandle()
{
}
@ -65,12 +59,16 @@ void LabelDefaultClickHandle::RestoreState( AudacityProject *pProject )
}
}
void LabelDefaultClickHandle::DoClick
(const wxMouseEvent &event, AudacityProject *pProject, TrackPanelCell *pCell)
UIHandle::Result LabelDefaultClickHandle::Click
(const TrackPanelMouseEvent &evt, AudacityProject *pProject)
{
LabelTrack *pLT = static_cast<LabelTrack*>(pCell);
using namespace RefreshCode;
// Redraw to show the change of text box selection status
UIHandle::Result result = RefreshAll;
if (event.LeftDown())
LabelTrack *pLT = static_cast<LabelTrack*>(evt.pCell);
if (evt.event.LeftDown())
{
SaveState( pProject );
@ -79,7 +77,7 @@ void LabelDefaultClickHandle::DoClick
Track *n = iter.First();
while (n) {
if (n->GetKind() == Track::Label && pCell != n) {
if (n->GetKind() == Track::Label && evt.pCell != n) {
LabelTrack *const lt = static_cast<LabelTrack*>(n);
lt->ResetFlags();
lt->Unselect();
@ -87,22 +85,6 @@ void LabelDefaultClickHandle::DoClick
n = iter.Next();
}
}
}
UIHandle::Result LabelDefaultClickHandle::Click
(const TrackPanelMouseEvent &evt, AudacityProject *pProject)
{
using namespace RefreshCode;
// Redraw to show the change of text box selection status
UIHandle::Result result = RefreshAll;
DoClick(evt.event, pProject, evt.pCell);
if (mpForward)
result |= mpForward->Click(evt, pProject);
else
// No drag or release follows
result |= Cancelled;
return result;
}
@ -110,19 +92,7 @@ UIHandle::Result LabelDefaultClickHandle::Click
UIHandle::Result LabelDefaultClickHandle::Drag
(const TrackPanelMouseEvent &evt, AudacityProject *pProject)
{
if (mpForward)
return mpForward->Drag(evt, pProject);
else
return RefreshCode::RefreshNone;
}
HitTestPreview LabelDefaultClickHandle::Preview
(const TrackPanelMouseEvent &evt, const AudacityProject *pProject)
{
if (mpForward)
return mpForward->Preview(evt, pProject);
else
return {};
return RefreshCode::RefreshNone;
}
UIHandle::Result LabelDefaultClickHandle::Release
@ -130,40 +100,12 @@ UIHandle::Result LabelDefaultClickHandle::Release
wxWindow *pParent)
{
mLabelState.reset();
if (mpForward)
return mpForward->Release(evt, pProject, pParent);
else
return RefreshCode::RefreshNone;
return RefreshCode::RefreshNone;
}
UIHandle::Result LabelDefaultClickHandle::Cancel(AudacityProject *pProject)
{
UIHandle::Result result = RefreshCode::RefreshNone;
if (mpForward)
result |= mpForward->Cancel(pProject);
RestoreState( pProject );
return result;
}
void LabelDefaultClickHandle::DrawExtras
(DrawingPass pass,
wxDC * dc, const wxRegion &updateRegion, const wxRect &panelRect)
{
UIHandle::DrawExtras(pass, dc, updateRegion, panelRect);
if (mpForward)
mpForward->DrawExtras(pass, dc, updateRegion, panelRect);
}
bool LabelDefaultClickHandle::StopsOnKeystroke()
{
return
(mpForward && mpForward->StopsOnKeystroke()) ||
UIHandle::StopsOnKeystroke();
}
void LabelDefaultClickHandle::OnProjectChange(AudacityProject *pProject)
{
if (mpForward)
return mpForward->OnProjectChange(pProject);
UIHandle::OnProjectChange(pProject);
}

View File

@ -18,29 +18,24 @@ class wxMouseEvent;
struct HitTestResult;
class LabelTrack;
// Adds some behavior to click, then calls through to other mouse handling.
class LabelDefaultClickHandle final : public UIHandle
// Used as a base class.
// Adds some behavior to clicks.
class LabelDefaultClickHandle /* not final */ : public UIHandle
{
LabelDefaultClickHandle();
LabelDefaultClickHandle(const LabelDefaultClickHandle&) = delete;
LabelDefaultClickHandle &operator=(const LabelDefaultClickHandle&) = delete;
public:
static LabelDefaultClickHandle& Instance();
LabelDefaultClickHandle();
virtual ~LabelDefaultClickHandle();
void DoClick
(const wxMouseEvent &event, AudacityProject *pProject, TrackPanelCell *pCell);
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;
// does not override Preview()
Result Release
(const TrackPanelMouseEvent &event, AudacityProject *pProject,
@ -48,17 +43,6 @@ public:
Result Cancel(AudacityProject *pProject) override;
void DrawExtras
(DrawingPass pass,
wxDC * dc, const wxRegion &updateRegion, const wxRect &panelRect)
override;
bool StopsOnKeystroke() override;
void OnProjectChange(AudacityProject *pProject) override;
UIHandle *mpForward {};
private:
struct LabelState;
std::unique_ptr< LabelState > mLabelState;

View File

@ -8,6 +8,7 @@ Paul Licameli split from TrackPanel.cpp
**********************************************************************/
#include "../../../Audacity.h"
#include "LabelGlyphHandle.h"
#include "../../../HitTestResult.h"
#include "../../../LabelTrack.h"
@ -90,6 +91,8 @@ LabelGlyphHandle::~LabelGlyphHandle()
UIHandle::Result LabelGlyphHandle::Click
(const TrackPanelMouseEvent &evt, AudacityProject *pProject)
{
auto result = LabelDefaultClickHandle::Click( evt, pProject );
TrackPanelCell *const pCell = evt.pCell;
const wxMouseEvent &event = evt.event;
const wxRect &rect = evt.rect;
@ -104,11 +107,11 @@ UIHandle::Result LabelGlyphHandle::Click
{
// The positive hit test should have ensured otherwise
//wxASSERT(false);
return RefreshCode::Cancelled;
result |= RefreshCode::Cancelled;
}
// redraw the track.
return RefreshCode::RefreshCell;
else
// redraw the track.
result |= RefreshCode::RefreshCell;
// handle shift+ctrl down
/*if (event.ShiftDown()) { // && event.ControlDown()) {
@ -117,19 +120,20 @@ UIHandle::Result LabelGlyphHandle::Click
return;
}*/
return RefreshCode::RefreshNone;
return result;
}
UIHandle::Result LabelGlyphHandle::Drag
(const TrackPanelMouseEvent &evt, AudacityProject *pProject)
{
auto result = LabelDefaultClickHandle::Drag( evt, pProject );
const wxMouseEvent &event = evt.event;
ViewInfo &viewInfo = pProject->GetViewInfo();
mpLT->HandleGlyphDragRelease(event, mRect, viewInfo, &viewInfo.selectedRegion);
// Refresh all so that the change of selection is redrawn in all tracks
return RefreshCode::RefreshAll | RefreshCode::DrawOverlays;
return result | RefreshCode::RefreshAll | RefreshCode::DrawOverlays;
}
HitTestPreview LabelGlyphHandle::Preview
@ -142,6 +146,7 @@ UIHandle::Result LabelGlyphHandle::Release
(const TrackPanelMouseEvent &evt, AudacityProject *pProject,
wxWindow *pParent)
{
auto result = LabelDefaultClickHandle::Release( evt, pProject, pParent );
mpLT->mOldEdge = 0;
const wxMouseEvent &event = evt.event;
@ -153,12 +158,13 @@ UIHandle::Result LabelGlyphHandle::Release
}
// Refresh all so that the change of selection is redrawn in all tracks
return RefreshCode::RefreshAll | RefreshCode::DrawOverlays;
return result | RefreshCode::RefreshAll | RefreshCode::DrawOverlays;
}
UIHandle::Result LabelGlyphHandle::Cancel(AudacityProject *pProject)
{
mpLT->mOldEdge = 0;
pProject->RollbackState();
return RefreshCode::RefreshAll;
auto result = LabelDefaultClickHandle::Cancel( pProject );
return result | RefreshCode::RefreshAll;
}

View File

@ -11,14 +11,14 @@ Paul Licameli split from TrackPanel.cpp
#ifndef __AUDACITY_LABEL_GLYPH_HANDLE__
#define __AUDACITY_LABEL_GLYPH_HANDLE__
#include "../../../UIHandle.h"
#include "LabelDefaultClickHandle.h"
#include <wx/gdicmn.h>
class wxMouseEvent;
struct HitTestResult;
class LabelTrack;
class LabelGlyphHandle final : public UIHandle
class LabelGlyphHandle final : public LabelDefaultClickHandle
{
LabelGlyphHandle();
LabelGlyphHandle(const LabelGlyphHandle&) = delete;

View File

@ -16,6 +16,7 @@ Paul Licameli split from TrackPanel.cpp
#include "../../../RefreshCode.h"
#include "../../../TrackPanelMouseEvent.h"
#include "../../../ViewInfo.h"
#include "../../../images/Cursors.h"
LabelTextHandle::LabelTextHandle()
{
@ -27,13 +28,23 @@ LabelTextHandle &LabelTextHandle::Instance()
return instance;
}
HitTestPreview LabelTextHandle::HitPreview()
{
static auto ibeamCursor =
::MakeCursor(wxCURSOR_IBEAM, IBeamCursorXpm, 17, 16);
return {
_("Click to edit label text"),
ibeamCursor.get()
};
}
HitTestResult LabelTextHandle::HitTest(const wxMouseEvent &event, LabelTrack *pLT)
{
// If Control is down, let the select handle be hit instead
if (!event.ControlDown() &&
pLT->OverATextBox(event.m_x, event.m_y) >= 0)
// There was no cursor change or status message for mousing over a label text box
return { {}, &Instance() };
return { HitPreview(), &Instance() };
return {};
}
@ -45,6 +56,8 @@ LabelTextHandle::~LabelTextHandle()
UIHandle::Result LabelTextHandle::Click
(const TrackPanelMouseEvent &evt, AudacityProject *pProject)
{
auto result = LabelDefaultClickHandle::Click( evt, pProject );
auto &selectionState = pProject->GetSelectionState();
TrackList *const tracks = pProject->GetTracks();
mChanger =
@ -98,14 +111,14 @@ UIHandle::Result LabelTextHandle::Click
if (!unsafe)
pProject->ModifyState(false);
return RefreshCode::RefreshCell | RefreshCode::UpdateSelection;
return result | RefreshCode::RefreshCell | RefreshCode::UpdateSelection;
}
UIHandle::Result LabelTextHandle::Drag
(const TrackPanelMouseEvent &evt, AudacityProject *pProject)
{
using namespace RefreshCode;
Result result = RefreshNone;
auto result = LabelDefaultClickHandle::Drag( evt, pProject );
const wxMouseEvent &event = evt.event;
auto pLT = mpLT.lock();
@ -138,13 +151,15 @@ UIHandle::Result LabelTextHandle::Drag
HitTestPreview LabelTextHandle::Preview
(const TrackPanelMouseEvent &evt, const AudacityProject *pProject)
{
return {};
return HitPreview();
}
UIHandle::Result LabelTextHandle::Release
(const TrackPanelMouseEvent &evt, AudacityProject *pProject,
wxWindow *pParent)
{
auto result = LabelDefaultClickHandle::Release( evt, pProject, pParent );
// Only selected a part of a text string and changed track selectedness.
// No undoable effects.
@ -162,7 +177,7 @@ UIHandle::Result LabelTextHandle::Release
if (event.LeftUp())
mLabelTrackStartXPos = -1;
return RefreshCode::RefreshNone;
return result | RefreshCode::RefreshNone;
}
UIHandle::Result LabelTextHandle::Cancel( AudacityProject *pProject )
@ -173,5 +188,6 @@ UIHandle::Result LabelTextHandle::Cancel( AudacityProject *pProject )
mChanger.release();
ViewInfo &viewInfo = pProject->GetViewInfo();
viewInfo.selectedRegion = mSelectedRegion;
return RefreshCode::RefreshAll;
auto result = LabelDefaultClickHandle::Cancel( pProject );
return result | RefreshCode::RefreshAll;
}

View File

@ -11,7 +11,7 @@ Paul Licameli split from TrackPanel.cpp
#ifndef __AUDACITY_LABEL_TEXT_HANDLE__
#define __AUDACITY_LABEL_TEXT_HANDLE__
#include "../../../UIHandle.h"
#include "LabelDefaultClickHandle.h"
#include "../../../MemoryX.h"
#include "../../../SelectedRegion.h"
#include <wx/gdicmn.h>
@ -21,13 +21,15 @@ struct HitTestResult;
class LabelTrack;
class SelectionStateChanger;
class LabelTextHandle final : public UIHandle
class LabelTextHandle final : public LabelDefaultClickHandle
{
LabelTextHandle();
LabelTextHandle(const LabelTextHandle&) = delete;
LabelTextHandle &operator=(const LabelTextHandle&) = delete;
static LabelTextHandle& Instance();
static HitTestPreview HitPreview();
public:
static HitTestResult HitTest(const wxMouseEvent &event, LabelTrack *pLT);

View File

@ -20,49 +20,20 @@ Paul Licameli split from TrackPanel.cpp
#include "../../../HitTestResult.h"
#include "../../../Project.h"
#include "../../../TrackPanelMouseEvent.h"
#include "../../../toolbars/ToolsToolBar.h"
HitTestResult LabelTrack::HitTest
HitTestResult LabelTrack::DetailedHitTest
(const TrackPanelMouseEvent &evt,
const AudacityProject *pProject)
const AudacityProject *pProject, int, bool)
{
// PRL: Maybe I did too much work to preserve old behavior, but anyway,
// this unusually combines parts of two or more hit test results.
HitTestResult result;
const wxMouseEvent &event = evt.event;
// Try label movement handles first
result = LabelGlyphHandle::HitTest(event, this);
// Hit test may request refresh even if a miss
auto refreshResult = result.preview.refreshCode;
if ( !result.handle ) {
if ( !result.handle )
// Missed glyph, try text box
// This hit test does not define its own messages or cursor
HitTestResult defaultResult = Track::HitTest(evt, pProject);
if (!defaultResult.handle) {
// In case of multi tool, default to selection.
const ToolsToolBar *const pTtb = pProject->GetToolsToolBar();
if (pTtb->IsDown(multiTool))
defaultResult = SelectHandle::HitTest(evt, pProject, this);
}
result = LabelTextHandle::HitTest(event, this);
if (result.handle)
// Use any cursor or status message change from catchall,
// But let the text ui handle pass
result.preview = defaultResult.preview;
else
result = defaultResult;
}
// Now attach some common extra work to the click action
LabelDefaultClickHandle::Instance().mpForward = result.handle;
result.handle = &LabelDefaultClickHandle::Instance();
// Don't lose the refresh result side effect of the glyph
// hit test
result.preview.refreshCode |= refreshResult;
return result;
}

View File

@ -21,44 +21,18 @@ Paul Licameli split from TrackPanel.cpp
#include "../../../../TrackPanelMouseEvent.h"
#include "../../../ui/SelectHandle.h"
#include "StretchHandle.h"
#include "../../../../toolbars/ToolsToolBar.h"
HitTestResult NoteTrack::HitTest
HitTestResult NoteTrack::DetailedHitTest
(const TrackPanelMouseEvent &event,
const AudacityProject *pProject)
const AudacityProject *pProject, int, bool )
{
const ToolsToolBar *const pTtb = pProject->GetToolsToolBar();
// If the cursor is in the hot zone for stretching, that takes precedence
// over selection, but it didn't take precedence over other hits.
// That was the old logic, and maybe I tried too hard to preserve it just so.
// PRL.
// Eligible for stretch?
HitTestResult result1;
HitTestResult result;
#ifdef USE_MIDI
StretchHandle::StretchState state;
result1 = StretchHandle::HitTest( event, pProject, this, state );
result = StretchHandle::HitTest( event, pProject, this, state );
#endif
// But some other non-select tool like zoom may take priority.
HitTestResult result = Track::HitTest(event, pProject);
if (result.preview.cursor &&
!(result1.preview.cursor && pTtb->GetCurrentTool() == selectTool))
return result;
if (pTtb->IsDown(multiTool)) {
// Default to selection
if (!result1.preview.cursor &&
NULL != (result =
SelectHandle::HitTest(event, pProject, this)).preview.cursor)
return result;
}
// Do stretch!
if (result1.preview.cursor)
return result1;
return result;
}

View File

@ -23,47 +23,66 @@ Paul Licameli split from TrackPanel.cpp
#include "SampleHandle.h"
#include "../../../ui/TimeShiftHandle.h"
HitTestResult WaveTrack::HitTest
HitTestResult WaveTrack::DetailedHitTest
(const TrackPanelMouseEvent &event,
const AudacityProject *pProject)
const AudacityProject *pProject, int currentTool, bool bMultiTool)
{
// FIXME: Should similar logic apply to NoteTrack (#if defined(USE_MIDI)) ?
// From here on the order in which we hit test determines
// which tool takes priority in the rare cases where it
// could be more than one.
// This is the only override of Track::DetailedHitTest that still
// depends on the state of the Tools toolbar.
// If that toolbar were eliminated, this could simplify to a sequence of
// hit test routines describable by a table.
// This hit was always tested first no matter which tool:
HitTestResult result = CutlineHandle::HitTest(event.event, event.rect, pProject, this);
if (result.preview.cursor)
return result;
WaveTrack *const wavetrack = static_cast<WaveTrack*>(event.pCell);
bool isWaveform = (wavetrack->GetDisplay() == WaveTrack::Waveform);
result = Track::HitTest(event, pProject);
if (result.preview.cursor)
return result;
if (bMultiTool && event.event.CmdDown())
// Ctrl modifier key in multi-tool overrides everything else
// (But this does not do the time shift constrained to the vertical only,
// which is what happens when you hold Ctrl in the Time Shift tool mode)
return TimeShiftHandle::HitAnywhere(pProject);
const ToolsToolBar *const pTtb = pProject->GetToolsToolBar();
if (pTtb->IsDown(multiTool)) {
// Replicate some of the logic of TrackPanel::DetermineToolToUse
int currentTool = -1;
if (event.event.CmdDown())
result = TimeShiftHandle::HitAnywhere(pProject);
else if (NULL !=
(result = EnvelopeHandle::WaveTrackHitTest(event.event, event.rect, pProject, this))
.preview.cursor)
;
else if (NULL != (result =
TimeShiftHandle::HitTest(event.event, event.rect, pProject)).preview.cursor)
;
else if (NULL != (result =
SampleHandle::HitTest(event.event, event.rect, pProject, this)).preview.cursor)
;
else if (NULL != (result =
SelectHandle::HitTest(event, pProject, this)).preview.cursor)
// default of all other hit tests
;
// Some special targets are not drawn in spectrogram,
// so don't hit them in such views.
else if (isWaveform) {
HitTestResult result;
if (NULL !=
(result = CutlineHandle::HitTest
(event.event, event.rect, pProject, this))
.preview.cursor)
// This overriding test applies in all tools
return result;
else if (bMultiTool) {
// Conditional hit tests
// If Tools toolbar were eliminated, we would keep these
// The priority of these, in case more than one might apply at one
// point, seems arbitrary
if (NULL != (result = EnvelopeHandle::WaveTrackHitTest
(event.event, event.rect, pProject, *this))
.preview.cursor)
;
else if (NULL != (result = TimeShiftHandle::HitTest
(event.event, event.rect, pProject)).preview.cursor)
// This is the hit test on the "grips" drawn left and
// right in Multi only
;
else if (NULL != (result = SampleHandle::HitTest
(event.event, event.rect, pProject, this)).preview.cursor)
;
return result;
}
else switch ( currentTool ) {
// Unconditional hits appropriate to the tool
// If tools toolbar were eliminated, we would eliminate these
case envelopeTool:
return EnvelopeHandle::HitAnywhere(pProject);
case drawTool:
return SampleHandle::HitAnywhere(event.event, pProject);
default:
break;
}
}
return result;
return {};
}
std::shared_ptr<TrackControls> WaveTrack::GetControls()

View File

@ -13,25 +13,17 @@ Paul Licameli split from TrackPanel.cpp
#include "TimeTrackVRulerControls.h"
#include "../../../HitTestResult.h"
#include "../../../TrackPanelMouseEvent.h"
#include "../../../Project.h"
#include "../../../toolbars/ToolsToolBar.h"
#include "../../ui/EnvelopeHandle.h"
HitTestResult TimeTrack::HitTest
HitTestResult TimeTrack::DetailedHitTest
(const TrackPanelMouseEvent &event,
const AudacityProject *pProject)
const AudacityProject *pProject, int, bool)
{
HitTestResult result = Track::HitTest(event, pProject);
if (result.preview.cursor)
return result;
const ToolsToolBar *const pTtb = pProject->GetToolsToolBar();
if (pTtb->IsDown(multiTool))
// No hit test --unconditional availability.
result = EnvelopeHandle::HitAnywhere(pProject);
return result;
return EnvelopeHandle::TimeTrackHitTest
( event.event, event.rect, pProject, *this );
}
std::shared_ptr<TrackControls> TimeTrack::GetControls()

View File

@ -62,39 +62,76 @@ HitTestResult EnvelopeHandle::HitAnywhere(const AudacityProject *pProject)
};
}
namespace {
void GetTimeTrackData
(const AudacityProject &project, const TimeTrack &tt,
double &dBRange, bool &dB, float &zoomMin, float &zoomMax)
{
const auto &viewInfo = project.GetViewInfo();
dBRange = viewInfo.dBr;
dB = tt.GetDisplayLog();
zoomMin = tt.GetRangeLower(), zoomMax = tt.GetRangeUpper();
if (dB) {
// MB: silly way to undo the work of GetWaveYPos while still getting a logarithmic scale
zoomMin = LINEAR_TO_DB(std::max(1.0e-7, double(dBRange))) / dBRange + 1.0;
zoomMax = LINEAR_TO_DB(std::max(1.0e-7, double(zoomMax))) / dBRange + 1.0;
}
}
}
HitTestResult EnvelopeHandle::TimeTrackHitTest
(const wxMouseEvent &event, const wxRect &rect,
const AudacityProject *pProject, TimeTrack &tt)
{
auto envelope = tt.GetEnvelope();
if (!envelope)
return {};
bool dB;
double dBRange;
float zoomMin, zoomMax;
GetTimeTrackData( *pProject, tt, dBRange, dB, zoomMin, zoomMax);
return EnvelopeHandle::HitEnvelope
(event, rect, pProject, envelope, zoomMin, zoomMax, dB, dBRange);
}
HitTestResult EnvelopeHandle::WaveTrackHitTest
(const wxMouseEvent &event, const wxRect &rect,
const AudacityProject *pProject, Cell *pCell)
const AudacityProject *pProject, WaveTrack &wt)
{
const ViewInfo &viewInfo = pProject->GetViewInfo();
Track *const pTrack = static_cast<Track*>(pCell);
/// method that tells us if the mouse event landed on an
/// envelope boundary.
if (pTrack->GetKind() != Track::Wave)
return {};
WaveTrack *const wavetrack = static_cast<WaveTrack*>(pTrack);
Envelope *const envelope = wavetrack->GetEnvelopeAtX(event.GetX());
const Envelope *const envelope = wt.GetEnvelopeAtX(event.GetX());
if (!envelope)
return {};
const int displayType = wavetrack->GetDisplay();
const int displayType = wt.GetDisplay();
// Not an envelope hit, unless we're using a type of wavetrack display
// suitable for envelopes operations, ie one of the Wave displays.
if (displayType != WaveTrack::Waveform)
return {}; // No envelope, not a hit, so return.
// Get envelope point, range 0.0 to 1.0
const bool dB = !wavetrack->GetWaveformSettings().isLinear();
const double envValue =
envelope->GetValue(viewInfo.PositionToTime(event.m_x, rect.x));
const bool dB = !wt.GetWaveformSettings().isLinear();
float zoomMin, zoomMax;
wavetrack->GetDisplayBounds(&zoomMin, &zoomMax);
wt.GetDisplayBounds(&zoomMin, &zoomMax);
const float dBRange = wavetrack->GetWaveformSettings().dBRange;
const float dBRange = wt.GetWaveformSettings().dBRange;
return EnvelopeHandle::HitEnvelope
(event, rect, pProject, envelope, zoomMin, zoomMax, dB, dBRange);
}
HitTestResult EnvelopeHandle::HitEnvelope
(const wxMouseEvent &event, const wxRect &rect, const AudacityProject *pProject,
const Envelope *envelope, float zoomMin, float zoomMax,
bool dB, float dBRange)
{
const ViewInfo &viewInfo = pProject->GetViewInfo();
const double envValue =
envelope->GetValue(viewInfo.PositionToTime(event.m_x, rect.x));
// Get y position of envelope point.
int yValue = GetWaveYPos(envValue,
@ -187,14 +224,7 @@ UIHandle::Result EnvelopeHandle::Click
auto clickedEnvelope = tt->GetEnvelope();
if (!clickedEnvelope)
return Cancelled;
mLog = tt->GetDisplayLog();
mLower = tt->GetRangeLower(), mUpper = tt->GetRangeUpper();
if (mLog) {
// MB: silly way to undo the work of GetWaveYPos while still getting a logarithmic scale
mdBRange = viewInfo.dBr;
mLower = LINEAR_TO_DB(std::max(1.0e-7, double(mLower))) / mdBRange + 1.0;
mUpper = LINEAR_TO_DB(std::max(1.0e-7, double(mUpper))) / mdBRange + 1.0;
}
GetTimeTrackData( *pProject, *tt, mdBRange, mLog, mLower, mUpper);
mEnvelopeEditor =
std::make_unique< EnvelopeEditor >( *clickedEnvelope, false );
mEnvelopeEditorRight.reset();

View File

@ -17,9 +17,11 @@ Paul Licameli split from TrackPanel.cpp
class wxMouseEvent;
#include <wx/gdicmn.h>
class Envelope;
class EnvelopeEditor;
struct HitTestResult;
class ViewInfo;
class TimeTrack;
class WaveTrack;
class EnvelopeHandle final : public UIHandle
@ -30,11 +32,20 @@ class EnvelopeHandle final : public UIHandle
static EnvelopeHandle& Instance();
static HitTestPreview HitPreview(const AudacityProject *pProject, bool unsafe);
static HitTestResult HitEnvelope
(const wxMouseEvent &event, const wxRect &rect,
const AudacityProject *pProject,
const Envelope *envelope, float zoomMin, float zoomMax,
bool dB, float dBRange);
public:
static HitTestResult HitAnywhere(const AudacityProject *pProject);
static HitTestResult TimeTrackHitTest
(const wxMouseEvent &event, const wxRect &rect,
const AudacityProject *pProject, TimeTrack &tt);
static HitTestResult WaveTrackHitTest
(const wxMouseEvent &event, const wxRect &rect,
const AudacityProject *pProject, Cell *pCell);
const AudacityProject *pProject, WaveTrack &wt);
virtual ~EnvelopeHandle();

View File

@ -28,34 +28,34 @@ HitTestResult Track::HitTest
const AudacityProject *pProject)
{
const ToolsToolBar * pTtb = pProject->GetToolsToolBar();
// Unless in Multimode keep using the current tool.
const bool isMultiTool = pTtb->IsDown(multiTool);
if (!isMultiTool) {
switch (pTtb->GetCurrentTool()) {
case envelopeTool:
// Pass "false" for unsafe -- let the tool decide to cancel itself
return EnvelopeHandle::HitAnywhere(pProject);
case drawTool:
return SampleHandle::HitAnywhere(event.event, pProject);
case zoomTool:
return ZoomHandle::HitAnywhere(event.event, pProject);
case slideTool:
return TimeShiftHandle::HitAnywhere(pProject);
case selectTool:
return SelectHandle::HitTest(event, pProject, this);
const auto currentTool = pTtb->GetCurrentTool();
default:
// fallthru
;
}
}
if ( !isMultiTool && currentTool == zoomTool )
// Zoom tool is a non-selecting tool that takes precedence in all tracks
// over all other tools, no matter what detail you point at.
return ZoomHandle::HitAnywhere(event.event, pProject);
// Replicate some of the logic of TrackPanel::DetermineToolToUse
HitTestResult result;
// In other tools, let subclasses determine detailed hits.
HitTestResult result =
DetailedHitTest( event, pProject, currentTool, isMultiTool );
if (isMultiTool)
// If there is no detailed hit for the subclass, there are still some
// general cases.
// Sliding applies in more than one track type.
if ( !result.handle && !isMultiTool && currentTool == slideTool )
result = TimeShiftHandle::HitAnywhere(pProject);
// Let the multi-tool right-click handler apply only in default of all
// other detailed hits.
if ( !result.handle && isMultiTool )
result = ZoomHandle::HitTest(event.event, pProject);
// Finally, default of all is adjustment of the selection box.
if ( !result.handle && ( isMultiTool || currentTool == selectTool) )
result = SelectHandle::HitTest(event, pProject, this);
return result;
}