1
0
mirror of https://github.com/cookiengineer/audacity synced 2025-06-16 16:10:06 +02:00

Wave track affordances

This commit is contained in:
Vitaly Sverchinsky 2021-07-15 14:40:50 +03:00 committed by Panagiotis Vasilopoulos
parent 4f43326c77
commit 5672a179da
No known key found for this signature in database
GPG Key ID: FD806FDB3B2C5270
9 changed files with 228 additions and 29 deletions

View File

@ -823,6 +823,8 @@ list( APPEND SOURCES
tracks/playabletrack/wavetrack/ui/SpectrumVZoomHandle.h tracks/playabletrack/wavetrack/ui/SpectrumVZoomHandle.h
tracks/playabletrack/wavetrack/ui/SpectrumView.cpp tracks/playabletrack/wavetrack/ui/SpectrumView.cpp
tracks/playabletrack/wavetrack/ui/SpectrumView.h tracks/playabletrack/wavetrack/ui/SpectrumView.h
tracks/playabletrack/wavetrack/ui/WaveTrackAffordanceControls.cpp
tracks/playabletrack/wavetrack/ui/WaveTrackAffordanceControls.h
tracks/playabletrack/wavetrack/ui/WaveTrackControls.cpp tracks/playabletrack/wavetrack/ui/WaveTrackControls.cpp
tracks/playabletrack/wavetrack/ui/WaveTrackControls.h tracks/playabletrack/wavetrack/ui/WaveTrackControls.h
tracks/playabletrack/wavetrack/ui/WaveTrackShifter.cpp tracks/playabletrack/wavetrack/ui/WaveTrackShifter.cpp

View File

@ -172,7 +172,8 @@ ChooseColorSet( float bin0, float bin1, float selBinLo,
void DrawClipSpectrum(TrackPanelDrawingContext &context, void DrawClipSpectrum(TrackPanelDrawingContext &context,
WaveTrackCache &waveTrackCache, WaveTrackCache &waveTrackCache,
const WaveClip *clip, const WaveClip *clip,
const wxRect & rect) const wxRect & rect,
bool selected)
{ {
auto &dc = context.dc; auto &dc = context.dc;
const auto artist = TrackArtist::Get( context ); const auto artist = TrackArtist::Get( context );
@ -608,13 +609,19 @@ void DrawClipSpectrum(TrackPanelDrawingContext &context,
// Draw clip edges, as also in waveform view, which improves the appearance // Draw clip edges, as also in waveform view, which improves the appearance
// of split views // of split views
params.DrawClipEdges( dc, rect ); {
//increase virtual view size by px to hide edges that should not be visible
auto clipRect = ClipParameters::GetClipRect(*clip, zoomInfo, rect.Inflate(1, 0), 1);
if (!clipRect.IsEmpty())
TrackArt::DrawClipEdges(dc, clipRect, selected);
}
} }
} }
void SpectrumView::DoDraw( TrackPanelDrawingContext &context, void SpectrumView::DoDraw(TrackPanelDrawingContext& context,
const WaveTrack *track, const WaveTrack* track,
const WaveClip* selectedClip,
const wxRect & rect ) const wxRect & rect )
{ {
const auto artist = TrackArtist::Get( context ); const auto artist = TrackArtist::Get( context );
@ -625,7 +632,7 @@ void SpectrumView::DoDraw( TrackPanelDrawingContext &context,
WaveTrackCache cache(track->SharedPointer<const WaveTrack>()); WaveTrackCache cache(track->SharedPointer<const WaveTrack>());
for (const auto &clip: track->GetClips()) for (const auto &clip: track->GetClips())
DrawClipSpectrum( context, cache, clip.get(), rect ); DrawClipSpectrum( context, cache, clip.get(), rect, clip.get() == selectedClip );
DrawBoldBoundaries( context, track, rect ); DrawBoldBoundaries( context, track, rect );
} }
@ -653,14 +660,18 @@ void SpectrumView::Draw(
wxAntialiasMode aamode = dc.GetGraphicsContext()->GetAntialiasMode(); wxAntialiasMode aamode = dc.GetGraphicsContext()->GetAntialiasMode();
dc.GetGraphicsContext()->SetAntialiasMode(wxANTIALIAS_NONE); dc.GetGraphicsContext()->SetAntialiasMode(wxANTIALIAS_NONE);
#endif #endif
auto waveTrackView = GetWaveTrackView().lock();
wxASSERT(waveTrackView.use_count());
DoDraw( context, wt.get(), rect ); auto seletedClip = waveTrackView->GetSelectedClip().lock();
DoDraw( context, wt.get(), seletedClip.get(), rect );
#if defined(__WXMAC__) #if defined(__WXMAC__)
dc.GetGraphicsContext()->SetAntialiasMode(aamode); dc.GetGraphicsContext()->SetAntialiasMode(aamode);
#endif #endif
} }
CommonTrackView::Draw( context, rect, iPass ); WaveTrackSubView::Draw( context, rect, iPass );
} }
static const WaveTrackSubViews::RegisteredFactory key{ static const WaveTrackSubViews::RegisteredFactory key{

View File

@ -38,6 +38,7 @@ private:
static void DoDraw( TrackPanelDrawingContext &context, static void DoDraw( TrackPanelDrawingContext &context,
const WaveTrack *track, const WaveTrack *track,
const WaveClip* selectedClip,
const wxRect & rect ); const wxRect & rect );
std::vector<UIHandlePtr> DetailedHitTest( std::vector<UIHandlePtr> DetailedHitTest(

View File

@ -0,0 +1,105 @@
/*!********************************************************************
*
Audacity: A Digital Audio Editor
WaveTrackAffordanceControls.cpp
Vitaly Sverchinsky
**********************************************************************/
#include "WaveTrackAffordanceControls.h"
#include <wx/dc.h>
#include "../../../../AllThemeResources.h"
#include "../../../../TrackPanelMouseEvent.h"
#include "../../../../TrackArtist.h"
#include "../../../../TrackPanelDrawingContext.h"
#include "../../../../ViewInfo.h"
#include "../../../../WaveTrack.h"
#include "../../../../WaveClip.h"
#include "../../../ui/AffordanceHandle.h"
#include "WaveTrackView.h"//need only ClipParameters
WaveTrackAffordanceControls::WaveTrackAffordanceControls(const std::shared_ptr<Track>& pTrack)
: CommonTrackCell(pTrack)
{
}
std::vector<UIHandlePtr> WaveTrackAffordanceControls::HitTest(const TrackPanelMouseState& state, const AudacityProject* pProject)
{
mFocusClip.reset();
std::vector<UIHandlePtr> results;
const auto track = FindTrack();
const auto waveTrack = std::static_pointer_cast<WaveTrack>(track->SubstitutePendingChangedTrack());
const auto rect = state.rect;
auto px = state.state.m_x;
auto py = state.state.m_y;
auto& zoomInfo = ViewInfo::Get(*pProject);
for (const auto& clip : waveTrack->GetClips())
{
auto affordanceRect = ClipParameters::GetClipRect(*clip.get(), zoomInfo, rect);
if (affordanceRect.Contains(px, py))
{
results.push_back(AffordanceHandle::HitAnywhere(mAffordanceHandle, track));
mFocusClip = clip;
break;
}
}
return results;
}
void WaveTrackAffordanceControls::Draw(TrackPanelDrawingContext& context, const wxRect& rect, unsigned iPass)
{
if (iPass == TrackArtist::PassBackground) {
auto track = FindTrack();
const auto artist = TrackArtist::Get(context);
TrackArt::DrawBackgroundWithSelection(context, rect, track.get(), artist->blankSelectedBrush, artist->blankBrush);
const auto waveTrack = std::static_pointer_cast<WaveTrack>(track->SubstitutePendingChangedTrack());
const auto& zoomInfo = *artist->pZoomInfo;
context.dc.SetClippingRegion(rect);
auto px = context.lastState.m_x;
auto py = context.lastState.m_y;
for (const auto& clip : waveTrack->GetClips())
{
auto affordanceRect = ClipParameters::GetClipRect(
*clip.get(),
zoomInfo,
rect.Inflate(TrackArt::ClipFrameRadius, 0),
TrackArt::ClipFrameRadius
);
if (affordanceRect.IsEmpty())
continue;
auto selected = GetSelectedClip().lock() == clip;
auto highlight = selected || affordanceRect.Contains(px, py);
TrackArt::DrawClipAffordance(context.dc, affordanceRect, highlight, selected);
}
context.dc.DestroyClippingRegion();
}
}
std::weak_ptr<WaveClip> WaveTrackAffordanceControls::GetSelectedClip() const
{
if (auto handle = mAffordanceHandle.lock())
{
return handle->Clicked() ? mFocusClip : std::weak_ptr<WaveClip>();
}
return {};
}

View File

@ -0,0 +1,30 @@
/*!********************************************************************
*
Audacity: A Digital Audio Editor
WaveTrackAffordanceControls.h
Vitaly Sverchinsky
**********************************************************************/
#pragma once
#include "../../../ui/CommonTrackPanelCell.h"
class AffordanceHandle;
class WaveClip;
class AUDACITY_DLL_API WaveTrackAffordanceControls : public CommonTrackCell
{
std::weak_ptr<WaveClip> mFocusClip;
std::weak_ptr<AffordanceHandle> mAffordanceHandle;
public:
WaveTrackAffordanceControls(const std::shared_ptr<Track>& pTrack);
std::vector<UIHandlePtr> HitTest(const TrackPanelMouseState& state, const AudacityProject* pProject) override;
void Draw(TrackPanelDrawingContext& context, const wxRect& rect, unsigned iPass) override;
std::weak_ptr<WaveClip> GetSelectedClip() const;
};

View File

@ -38,8 +38,11 @@ Paul Licameli split from TrackPanel.cpp
#include "../../../ui/ButtonHandle.h" #include "../../../ui/ButtonHandle.h"
#include "../../../../TrackInfo.h" #include "../../../../TrackInfo.h"
#include "WaveTrackAffordanceControls.h"
namespace { namespace {
using WaveTrackSubViewPtrs = std::vector< std::shared_ptr< WaveTrackSubView > >; using WaveTrackSubViewPtrs = std::vector< std::shared_ptr< WaveTrackSubView > >;
// Structure that collects and modifies information on sub-view positions // Structure that collects and modifies information on sub-view positions
@ -760,6 +763,11 @@ void WaveTrackSubView::DrawBoldBoundaries(
} }
} }
std::weak_ptr<WaveTrackView> WaveTrackSubView::GetWaveTrackView() const
{
return mwWaveTrackView;
}
WaveTrackView &WaveTrackView::Get( WaveTrack &track ) WaveTrackView &WaveTrackView::Get( WaveTrack &track )
{ {
return static_cast< WaveTrackView& >( TrackView::Get( track ) ); return static_cast< WaveTrackView& >( TrackView::Get( track ) );
@ -1018,6 +1026,11 @@ WaveTrackView::GetAllSubViews()
return results; return results;
} }
std::shared_ptr<CommonTrackCell> WaveTrackView::DoGetAffordanceControls()
{
return std::make_shared<WaveTrackAffordanceControls>(FindTrack());
}
void WaveTrackView::DoSetMinimized( bool minimized ) void WaveTrackView::DoSetMinimized( bool minimized )
{ {
BuildSubViews(); BuildSubViews();
@ -1229,20 +1242,23 @@ ClipParameters::ClipParameters
} }
} }
void ClipParameters::DrawClipEdges( wxDC &dc, const wxRect &rect ) const wxRect ClipParameters::GetClipRect(const WaveClip& clip, const ZoomInfo& zoomInfo, const wxRect& viewRect, int clipOffsetX)
{ {
// Draw clip edges auto srs = 1. / static_cast<double>(clip.GetRate());
dc.SetPen(*wxGREY_PEN); //to prevent overlap left and right most samples with frame border
if (tpre < 0) { auto margin = .25 * srs;
AColor::Line(dc, auto edgeLeft = static_cast<wxInt64>(viewRect.GetLeft());
mid.x - 1, mid.y, auto edgeRight = static_cast<wxInt64>(viewRect.GetRight());
mid.x - 1, mid.y + rect.height); auto left = std::clamp(zoomInfo.TimeToPosition(clip.GetOffset() - margin, viewRect.x + clipOffsetX, true), edgeLeft, edgeRight);
} auto right = std::clamp(zoomInfo.TimeToPosition(clip.GetEndTime() - srs + margin, viewRect.x + clipOffsetX, true), edgeLeft, edgeRight);
if (tpost > t1) { if (right - left > 0)
AColor::Line(dc, {
mid.x + mid.width, mid.y, //after clamping we can expect that left and right
mid.x + mid.width, mid.y + rect.height); //are small enough to be put into int
} return wxRect(static_cast<int>(left), viewRect.y, static_cast<int>(right - left), viewRect.height);
}
//off the screen
return wxRect();
} }
void WaveTrackView::Reparent( const std::shared_ptr<Track> &parent ) void WaveTrackView::Reparent( const std::shared_ptr<Track> &parent )
@ -1252,6 +1268,17 @@ void WaveTrackView::Reparent( const std::shared_ptr<Track> &parent )
WaveTrackSubViews::ForEach( [&parent](WaveTrackSubView &subView){ WaveTrackSubViews::ForEach( [&parent](WaveTrackSubView &subView){
subView.Reparent( parent ); subView.Reparent( parent );
} ); } );
if (mpAffordanceCellControl)
mpAffordanceCellControl->Reparent(parent);
}
std::weak_ptr<WaveClip> WaveTrackView::GetSelectedClip()
{
if (auto affordance = std::dynamic_pointer_cast<WaveTrackAffordanceControls>(GetAffordanceControls()))
{
return affordance->GetSelectedClip();
}
return {};
} }
void WaveTrackView::BuildSubViews() const void WaveTrackView::BuildSubViews() const

View File

@ -21,6 +21,7 @@ class CutlineHandle;
class TranslatableString; class TranslatableString;
class WaveTrack; class WaveTrack;
class WaveTrackView; class WaveTrackView;
class WaveClip;
class AUDACITY_DLL_API WaveTrackSubView : public CommonTrackView class AUDACITY_DLL_API WaveTrackSubView : public CommonTrackView
{ {
@ -47,6 +48,8 @@ protected:
TrackPanelDrawingContext &context, const WaveTrack *track, TrackPanelDrawingContext &context, const WaveTrack *track,
const wxRect &rect ); const wxRect &rect );
std::weak_ptr<WaveTrackView> GetWaveTrackView() const;
private: private:
std::weak_ptr<UIHandle> mCloseHandle; std::weak_ptr<UIHandle> mCloseHandle;
std::weak_ptr<UIHandle> mAdjustHandle; std::weak_ptr<UIHandle> mAdjustHandle;
@ -122,6 +125,9 @@ public:
bool GetMultiView() const { return mMultiView; } bool GetMultiView() const { return mMultiView; }
void SetMultiView( bool value ) { mMultiView = value; } void SetMultiView( bool value ) { mMultiView = value; }
std::weak_ptr<WaveClip> GetSelectedClip();
private: private:
void BuildSubViews() const; void BuildSubViews() const;
void DoSetDisplay(Display display, bool exclusive = true); void DoSetDisplay(Display display, bool exclusive = true);
@ -141,6 +147,8 @@ private:
Refinement GetSubViews( const wxRect &rect ) override; Refinement GetSubViews( const wxRect &rect ) override;
protected: protected:
std::shared_ptr<CommonTrackCell> DoGetAffordanceControls() override;
void DoSetMinimized( bool minimized ) override; void DoSetMinimized( bool minimized ) override;
// Placements are in correspondence with the array of sub-views // Placements are in correspondence with the array of sub-views
@ -188,7 +196,9 @@ struct AUDACITY_DLL_API ClipParameters
wxRect mid; wxRect mid;
int leftOffset; int leftOffset;
void DrawClipEdges( wxDC &dc, const wxRect &rect ) const; // returns a clip rectangle restricted by viewRect,
// and with clipOffsetX - clip horizontal origin offset within view rect
static wxRect GetClipRect(const WaveClip& clip, const ZoomInfo& zoomInfo, const wxRect& viewRect, int clipOffsetX = 0);
}; };
#endif #endif

View File

@ -670,7 +670,8 @@ void DrawClipWaveform(TrackPanelDrawingContext &context,
const WaveClip *clip, const WaveClip *clip,
const wxRect & rect, const wxRect & rect,
bool dB, bool dB,
bool muted) bool muted,
bool selected)
{ {
auto &dc = context.dc; auto &dc = context.dc;
const auto artist = TrackArtist::Get( context ); const auto artist = TrackArtist::Get( context );
@ -900,7 +901,12 @@ void DrawClipWaveform(TrackPanelDrawingContext &context,
if (h == 0.0 && tOffset < 0.0) { if (h == 0.0 && tOffset < 0.0) {
TrackArt::DrawNegativeOffsetTrackArrows( context, rect ); TrackArt::DrawNegativeOffsetTrackArrows( context, rect );
} }
params.DrawClipEdges( dc, rect ); {
//increase virtual view size by px to hide edges that should not be visible
auto clipRect = ClipParameters::GetClipRect(*clip, zoomInfo, rect.Inflate(1, 0), 1);
if (!clipRect.IsEmpty())
TrackArt::DrawClipEdges(dc, clipRect, selected);
}
} }
void DrawTimeSlider( TrackPanelDrawingContext &context, void DrawTimeSlider( TrackPanelDrawingContext &context,
@ -967,7 +973,8 @@ void DrawTimeSlider( TrackPanelDrawingContext &context,
//#include "tracks/ui/TimeShiftHandle.h" //#include "tracks/ui/TimeShiftHandle.h"
void WaveformView::DoDraw(TrackPanelDrawingContext &context, void WaveformView::DoDraw(TrackPanelDrawingContext &context,
const WaveTrack *track, const WaveTrack *track,
const wxRect & rect, const WaveClip* selectedClip,
const wxRect& rect,
bool muted) bool muted)
{ {
auto &dc = context.dc; auto &dc = context.dc;
@ -988,10 +995,11 @@ void WaveformView::DoDraw(TrackPanelDrawingContext &context,
TrackArt::DrawBackgroundWithSelection( TrackArt::DrawBackgroundWithSelection(
context, rect, track, blankSelectedBrush, blankBrush ); context, rect, track, blankSelectedBrush, blankBrush );
for (const auto &clip: track->GetClips()) for (const auto& clip : track->GetClips())
{
DrawClipWaveform(context, track, clip.get(), rect, DrawClipWaveform(context, track, clip.get(), rect,
dB, muted); dB, muted, clip.get() == selectedClip);
}
DrawBoldBoundaries( context, track, rect ); DrawBoldBoundaries( context, track, rect );
const auto drawSliders = artist->drawSliders; const auto drawSliders = artist->drawSliders;
@ -1028,13 +1036,17 @@ void WaveformView::Draw(
dc.GetGraphicsContext()->SetAntialiasMode(wxANTIALIAS_NONE); dc.GetGraphicsContext()->SetAntialiasMode(wxANTIALIAS_NONE);
#endif #endif
DoDraw(context, wt.get(), rect, muted); auto waveTrackView = GetWaveTrackView().lock();
wxASSERT(waveTrackView.use_count());
auto selectedClip = waveTrackView->GetSelectedClip().lock();
DoDraw(context, wt.get(), selectedClip.get(), rect, muted);
#if defined(__WXMAC__) #if defined(__WXMAC__)
dc.GetGraphicsContext()->SetAntialiasMode(aamode); dc.GetGraphicsContext()->SetAntialiasMode(aamode);
#endif #endif
} }
CommonTrackView::Draw( context, rect, iPass ); WaveTrackSubView::Draw( context, rect, iPass );
} }
static const WaveTrackSubViews::RegisteredFactory key{ static const WaveTrackSubViews::RegisteredFactory key{

View File

@ -38,6 +38,7 @@ private:
const wxRect &rect, unsigned iPass ) override; const wxRect &rect, unsigned iPass ) override;
static void DoDraw(TrackPanelDrawingContext &context, static void DoDraw(TrackPanelDrawingContext &context,
const WaveTrack *track, const WaveTrack *track,
const WaveClip* selectedClip,
const wxRect & rect, const wxRect & rect,
bool muted); bool muted);