1
0
mirror of https://github.com/cookiengineer/audacity synced 2025-05-07 15:22:34 +02:00

Wave track affordances

This commit is contained in:
Vitaly Sverchinsky 2021-07-15 14:40:50 +03:00 committed by Paul Licameli
parent cfacf2fa09
commit 70a7238ee6
9 changed files with 228 additions and 29 deletions

View File

@ -825,6 +825,8 @@ list( APPEND SOURCES
tracks/playabletrack/wavetrack/ui/SpectrumVZoomHandle.h
tracks/playabletrack/wavetrack/ui/SpectrumView.cpp
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.h
tracks/playabletrack/wavetrack/ui/WaveTrackShifter.cpp

View File

@ -172,7 +172,8 @@ ChooseColorSet( float bin0, float bin1, float selBinLo,
void DrawClipSpectrum(TrackPanelDrawingContext &context,
WaveTrackCache &waveTrackCache,
const WaveClip *clip,
const wxRect & rect)
const wxRect & rect,
bool selected)
{
auto &dc = context.dc;
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
// 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,
const WaveTrack *track,
void SpectrumView::DoDraw(TrackPanelDrawingContext& context,
const WaveTrack* track,
const WaveClip* selectedClip,
const wxRect & rect )
{
const auto artist = TrackArtist::Get( context );
@ -625,7 +632,7 @@ void SpectrumView::DoDraw( TrackPanelDrawingContext &context,
WaveTrackCache cache(track->SharedPointer<const WaveTrack>());
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 );
}
@ -653,14 +660,18 @@ void SpectrumView::Draw(
wxAntialiasMode aamode = dc.GetGraphicsContext()->GetAntialiasMode();
dc.GetGraphicsContext()->SetAntialiasMode(wxANTIALIAS_NONE);
#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__)
dc.GetGraphicsContext()->SetAntialiasMode(aamode);
#endif
}
CommonTrackView::Draw( context, rect, iPass );
WaveTrackSubView::Draw( context, rect, iPass );
}
static const WaveTrackSubViews::RegisteredFactory key{

View File

@ -38,6 +38,7 @@ private:
static void DoDraw( TrackPanelDrawingContext &context,
const WaveTrack *track,
const WaveClip* selectedClip,
const wxRect & rect );
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 "../../../../TrackInfo.h"
#include "WaveTrackAffordanceControls.h"
namespace {
using WaveTrackSubViewPtrs = std::vector< std::shared_ptr< WaveTrackSubView > >;
// 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 )
{
return static_cast< WaveTrackView& >( TrackView::Get( track ) );
@ -1018,6 +1026,11 @@ WaveTrackView::GetAllSubViews()
return results;
}
std::shared_ptr<CommonTrackCell> WaveTrackView::DoGetAffordanceControls()
{
return std::make_shared<WaveTrackAffordanceControls>(FindTrack());
}
void WaveTrackView::DoSetMinimized( bool minimized )
{
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
dc.SetPen(*wxGREY_PEN);
if (tpre < 0) {
AColor::Line(dc,
mid.x - 1, mid.y,
mid.x - 1, mid.y + rect.height);
}
if (tpost > t1) {
AColor::Line(dc,
mid.x + mid.width, mid.y,
mid.x + mid.width, mid.y + rect.height);
}
auto srs = 1. / static_cast<double>(clip.GetRate());
//to prevent overlap left and right most samples with frame border
auto margin = .25 * srs;
auto edgeLeft = static_cast<wxInt64>(viewRect.GetLeft());
auto edgeRight = static_cast<wxInt64>(viewRect.GetRight());
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 (right - left > 0)
{
//after clamping we can expect that left and right
//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 )
@ -1252,6 +1268,17 @@ void WaveTrackView::Reparent( const std::shared_ptr<Track> &parent )
WaveTrackSubViews::ForEach( [&parent](WaveTrackSubView &subView){
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

View File

@ -21,6 +21,7 @@ class CutlineHandle;
class TranslatableString;
class WaveTrack;
class WaveTrackView;
class WaveClip;
class AUDACITY_DLL_API WaveTrackSubView : public CommonTrackView
{
@ -47,6 +48,8 @@ protected:
TrackPanelDrawingContext &context, const WaveTrack *track,
const wxRect &rect );
std::weak_ptr<WaveTrackView> GetWaveTrackView() const;
private:
std::weak_ptr<UIHandle> mCloseHandle;
std::weak_ptr<UIHandle> mAdjustHandle;
@ -122,6 +125,9 @@ public:
bool GetMultiView() const { return mMultiView; }
void SetMultiView( bool value ) { mMultiView = value; }
std::weak_ptr<WaveClip> GetSelectedClip();
private:
void BuildSubViews() const;
void DoSetDisplay(Display display, bool exclusive = true);
@ -141,6 +147,8 @@ private:
Refinement GetSubViews( const wxRect &rect ) override;
protected:
std::shared_ptr<CommonTrackCell> DoGetAffordanceControls() override;
void DoSetMinimized( bool minimized ) override;
// Placements are in correspondence with the array of sub-views
@ -188,7 +196,9 @@ struct AUDACITY_DLL_API ClipParameters
wxRect mid;
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

View File

@ -670,7 +670,8 @@ void DrawClipWaveform(TrackPanelDrawingContext &context,
const WaveClip *clip,
const wxRect & rect,
bool dB,
bool muted)
bool muted,
bool selected)
{
auto &dc = context.dc;
const auto artist = TrackArtist::Get( context );
@ -900,7 +901,12 @@ void DrawClipWaveform(TrackPanelDrawingContext &context,
if (h == 0.0 && tOffset < 0.0) {
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,
@ -967,7 +973,8 @@ void DrawTimeSlider( TrackPanelDrawingContext &context,
//#include "tracks/ui/TimeShiftHandle.h"
void WaveformView::DoDraw(TrackPanelDrawingContext &context,
const WaveTrack *track,
const wxRect & rect,
const WaveClip* selectedClip,
const wxRect& rect,
bool muted)
{
auto &dc = context.dc;
@ -988,10 +995,11 @@ void WaveformView::DoDraw(TrackPanelDrawingContext &context,
TrackArt::DrawBackgroundWithSelection(
context, rect, track, blankSelectedBrush, blankBrush );
for (const auto &clip: track->GetClips())
for (const auto& clip : track->GetClips())
{
DrawClipWaveform(context, track, clip.get(), rect,
dB, muted);
dB, muted, clip.get() == selectedClip);
}
DrawBoldBoundaries( context, track, rect );
const auto drawSliders = artist->drawSliders;
@ -1028,13 +1036,17 @@ void WaveformView::Draw(
dc.GetGraphicsContext()->SetAntialiasMode(wxANTIALIAS_NONE);
#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__)
dc.GetGraphicsContext()->SetAntialiasMode(aamode);
#endif
}
CommonTrackView::Draw( context, rect, iPass );
WaveTrackSubView::Draw( context, rect, iPass );
}
static const WaveTrackSubViews::RegisteredFactory key{

View File

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