mirror of
https://github.com/cookiengineer/audacity
synced 2025-05-07 15:22:34 +02:00
Cherry-pick some of PR#1207, Track affordances
This commit is contained in:
commit
731af5109a
@ -371,3 +371,7 @@ from there. Audacity will look for a file called "Pause.png".
|
||||
DEFINE_COLOUR( clrSpectro4Sel, wxColour( 191, 0, 0), wxT("Spectro4Sel") );
|
||||
DEFINE_COLOUR( clrSpectro5Sel, wxColour( 191, 191, 191), wxT("Spectro5Sel") );
|
||||
|
||||
DEFINE_COLOUR( clrClipAffordanceOutlinePen, wxColour( 0, 0, 0), wxT("ClipAffordanceOutlinePen") );
|
||||
DEFINE_COLOUR( clrClipAffordanceInactiveBrush, wxColour( 202, 202, 202), wxT("ClipAffordanceUnselectedBrush") );
|
||||
DEFINE_COLOUR( clrClipAffordanceActiveBrush, wxColour( 219, 219, 219), wxT("ClipAffordanceSelectedBrush") );
|
||||
DEFINE_COLOUR( clrClipAffordanceStroke, wxColour( 255, 255, 255), wxT("ClipAffordanceStroke") );
|
||||
|
@ -796,6 +796,8 @@ list( APPEND SOURCES
|
||||
tracks/labeltrack/ui/LabelTrackVRulerControls.h
|
||||
tracks/labeltrack/ui/LabelTrackView.cpp
|
||||
tracks/labeltrack/ui/LabelTrackView.h
|
||||
tracks/playabletrack/notetrack/ui/NoteTrackAffordanceControls.h
|
||||
tracks/playabletrack/notetrack/ui/NoteTrackAffordanceControls.cpp
|
||||
tracks/playabletrack/notetrack/ui/NoteTrackButtonHandle.cpp
|
||||
tracks/playabletrack/notetrack/ui/NoteTrackButtonHandle.h
|
||||
tracks/playabletrack/notetrack/ui/NoteTrackControls.cpp
|
||||
@ -825,6 +827,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
|
||||
@ -855,6 +859,8 @@ list( APPEND SOURCES
|
||||
|
||||
# Tracks UI
|
||||
|
||||
tracks/ui/AffordanceHandle.cpp
|
||||
tracks/ui/AffordanceHandle.h
|
||||
tracks/ui/BackgroundCell.cpp
|
||||
tracks/ui/BackgroundCell.h
|
||||
tracks/ui/ButtonHandle.cpp
|
||||
|
@ -56,6 +56,9 @@ audio tracks.
|
||||
|
||||
#include <wx/dc.h>
|
||||
|
||||
//Thickness of the clip frame outline, shown when clip is dragged
|
||||
static constexpr int ClipSelectionStrokeSize{ 1 };//px
|
||||
|
||||
TrackArtist::TrackArtist( TrackPanel *parent_ )
|
||||
: parent( parent_ )
|
||||
{
|
||||
@ -260,6 +263,60 @@ void TrackArtist::UpdatePrefs()
|
||||
SetColours(0);
|
||||
}
|
||||
|
||||
void TrackArt::DrawClipAffordance(wxDC& dc, const wxRect& rect, bool highlight, bool selected)
|
||||
{
|
||||
if (selected)
|
||||
{
|
||||
wxRect strokeRect{
|
||||
rect.x - ClipSelectionStrokeSize,
|
||||
rect.y,
|
||||
rect.width + ClipSelectionStrokeSize * 2,
|
||||
rect.height + ClipFrameRadius };
|
||||
dc.SetBrush(*wxTRANSPARENT_BRUSH);
|
||||
AColor::UseThemeColour(&dc, clrClipAffordanceStroke, clrClipAffordanceStroke);
|
||||
dc.DrawRoundedRectangle(strokeRect, ClipFrameRadius);
|
||||
}
|
||||
AColor::UseThemeColour(&dc, highlight ? clrClipAffordanceActiveBrush : clrClipAffordanceInactiveBrush, clrClipAffordanceOutlinePen);
|
||||
dc.DrawRoundedRectangle(wxRect(rect.x, rect.y + ClipSelectionStrokeSize, rect.width, rect.height + ClipFrameRadius), ClipFrameRadius);
|
||||
}
|
||||
|
||||
void TrackArt::DrawClipEdges(wxDC& dc, const wxRect& clipRect, bool selected)
|
||||
{
|
||||
dc.SetBrush(*wxTRANSPARENT_BRUSH);
|
||||
{
|
||||
AColor::UseThemeColour(&dc, -1, clrClipAffordanceOutlinePen);
|
||||
AColor::Line(dc,
|
||||
clipRect.GetLeft(), clipRect.GetTop(),
|
||||
clipRect.GetLeft(), clipRect.GetBottom());
|
||||
AColor::Line(dc,
|
||||
clipRect.GetRight(), clipRect.GetTop(),
|
||||
clipRect.GetRight(), clipRect.GetBottom());
|
||||
}
|
||||
if(selected)
|
||||
{
|
||||
if constexpr (ClipSelectionStrokeSize == 1)
|
||||
{
|
||||
AColor::UseThemeColour(&dc, -1, clrClipAffordanceStroke);
|
||||
AColor::Line(dc,
|
||||
clipRect.GetLeft() - ClipSelectionStrokeSize, clipRect.GetTop(),
|
||||
clipRect.GetLeft() - ClipSelectionStrokeSize, clipRect.GetBottom());
|
||||
AColor::Line(dc,
|
||||
clipRect.GetRight() + ClipSelectionStrokeSize, clipRect.GetTop(),
|
||||
clipRect.GetRight() + ClipSelectionStrokeSize, clipRect.GetBottom());
|
||||
}
|
||||
else if constexpr (ClipSelectionStrokeSize > 1)
|
||||
{
|
||||
AColor::UseThemeColour(&dc, clrClipAffordanceStroke, clrClipAffordanceStroke);
|
||||
dc.DrawRectangle(wxRect(
|
||||
clipRect.GetLeft() - ClipSelectionStrokeSize, clipRect.GetTop(),
|
||||
ClipSelectionStrokeSize, clipRect.GetHeight()));
|
||||
dc.DrawRectangle(wxRect(
|
||||
clipRect.GetRight() + 1, clipRect.GetTop(),
|
||||
ClipSelectionStrokeSize, clipRect.GetHeight()));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Draws the sync-lock bitmap, tiled; always draws stationary relative to the DC
|
||||
//
|
||||
// AWD: now that the tiles don't link together, we're drawing a tilted grid, at
|
||||
|
@ -38,6 +38,14 @@ class ZoomInfo;
|
||||
|
||||
namespace TrackArt {
|
||||
|
||||
static constexpr int ClipFrameRadius{ 6 };
|
||||
|
||||
AUDACITY_DLL_API
|
||||
void DrawClipAffordance(wxDC& dc, const wxRect& affordanceRect, bool highlight = false, bool selected = false);
|
||||
|
||||
AUDACITY_DLL_API
|
||||
void DrawClipEdges(wxDC& dc, const wxRect& clipRect, bool selected = false);
|
||||
|
||||
// Helper: draws the "sync-locked" watermark tiled to a rectangle
|
||||
AUDACITY_DLL_API
|
||||
void DrawSyncLockTiles(
|
||||
|
@ -1270,7 +1270,61 @@ struct VRulersAndChannels final : TrackPanelGroup {
|
||||
wxCoord mLeftOffset;
|
||||
};
|
||||
|
||||
// n channels with vertical rulers, alternating with n - 1 resizers;
|
||||
//Simply fills area using specified brush and outlines borders
|
||||
class EmptyPanelRect final : public CommonTrackPanelCell
|
||||
{
|
||||
int mFillBrushName;
|
||||
public:
|
||||
explicit EmptyPanelRect(int fillBrushName)
|
||||
: mFillBrushName(fillBrushName)
|
||||
{
|
||||
}
|
||||
|
||||
~EmptyPanelRect() { }
|
||||
|
||||
void Draw(TrackPanelDrawingContext& context, const wxRect& rect, unsigned iPass)
|
||||
{
|
||||
if (iPass == TrackArtist::PassBackground)
|
||||
{
|
||||
context.dc.SetPen(*wxTRANSPARENT_PEN);
|
||||
AColor::UseThemeColour(&context.dc, mFillBrushName);
|
||||
context.dc.DrawRectangle(rect);
|
||||
wxRect bevel(rect.x, rect.y, rect.width - 1, rect.height - 1);
|
||||
AColor::BevelTrackInfo(context.dc, true, bevel, false);
|
||||
}
|
||||
}
|
||||
|
||||
std::shared_ptr<Track> DoFindTrack() override
|
||||
{
|
||||
return {};
|
||||
}
|
||||
|
||||
std::vector<UIHandlePtr> HitTest(const TrackPanelMouseState& state, const AudacityProject* pProject)
|
||||
{
|
||||
return {};
|
||||
}
|
||||
};
|
||||
|
||||
//Simply place children one after another horizontally, without any specific logic
|
||||
struct HorizontalGroup final : TrackPanelGroup {
|
||||
|
||||
Refinement mRefinement;
|
||||
|
||||
HorizontalGroup(Refinement refinement)
|
||||
: mRefinement(std::move(refinement))
|
||||
{
|
||||
}
|
||||
|
||||
Subdivision Children(const wxRect& /*rect*/) override
|
||||
{
|
||||
return { Axis::X, mRefinement };
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
|
||||
// optional affordance area, and n channels with vertical rulers,
|
||||
// alternating with n - 1 resizers;
|
||||
// each channel-ruler pair might be divided into multiple views
|
||||
struct ChannelGroup final : TrackPanelGroup {
|
||||
ChannelGroup( const std::shared_ptr< Track > &pTrack, wxCoord leftOffset )
|
||||
@ -1283,8 +1337,19 @@ struct ChannelGroup final : TrackPanelGroup {
|
||||
const auto channels = TrackList::Channels( mpTrack.get() );
|
||||
const auto pLast = *channels.rbegin();
|
||||
wxCoord yy = rect.GetTop();
|
||||
for ( auto channel : channels ) {
|
||||
for ( auto channel : channels )
|
||||
{
|
||||
auto &view = TrackView::Get( *channel );
|
||||
if (auto affordance = view.GetAffordanceControls())
|
||||
{
|
||||
Refinement hgroup {
|
||||
std::make_pair(rect.GetLeft() + 1, std::make_shared<EmptyPanelRect>(channel->GetSelected() ? clrTrackInfoSelected : clrTrackInfo)),
|
||||
std::make_pair(mLeftOffset, affordance)
|
||||
};
|
||||
refinement.emplace_back(yy, std::make_shared<HorizontalGroup>(hgroup));
|
||||
yy += kAffordancesAreaHeight;
|
||||
}
|
||||
|
||||
auto height = view.GetHeight();
|
||||
rect.SetTop( yy );
|
||||
rect.SetHeight( height - kSeparatorThickness );
|
||||
@ -1444,6 +1509,9 @@ struct Subgroup final : TrackPanelGroup {
|
||||
for ( auto channel : TrackList::Channels( leader ) ) {
|
||||
auto &view = TrackView::Get( *channel );
|
||||
height += view.GetHeight();
|
||||
|
||||
if (view.GetAffordanceControls())
|
||||
height += kAffordancesAreaHeight;
|
||||
}
|
||||
refinement.emplace_back( yy,
|
||||
std::make_shared< ResizingChannelGroup >(
|
||||
|
@ -101,6 +101,7 @@ private:
|
||||
// See big pictorial comment in TrackPanel.cpp for explanation of these numbers
|
||||
enum : int {
|
||||
// constants related to y coordinates in the track panel
|
||||
kAffordancesAreaHeight = 20,
|
||||
kTopInset = 4,
|
||||
kTopMargin = kTopInset + kBorderThickness,
|
||||
kBottomMargin = kShadowThickness + kBorderThickness,
|
||||
|
@ -0,0 +1,93 @@
|
||||
/*!********************************************************************
|
||||
*
|
||||
Audacity: A Digital Audio Editor
|
||||
|
||||
NoteTrackAffordanceControls.cpp
|
||||
|
||||
Vitaly Sverchinsky
|
||||
|
||||
**********************************************************************/
|
||||
|
||||
#include "NoteTrackAffordanceControls.h"
|
||||
|
||||
#include <wx/dc.h>
|
||||
|
||||
#include "../../../ui/AffordanceHandle.h"
|
||||
#include "../../../../AllThemeResources.h"
|
||||
#include "../../../../AColor.h"
|
||||
#include "../../../../NoteTrack.h"
|
||||
#include "../../../../ViewInfo.h"
|
||||
#include "../../../../TrackArtist.h"
|
||||
#include "../../../../TrackPanelMouseEvent.h"
|
||||
#include "../../../../TrackPanelDrawingContext.h"
|
||||
|
||||
#include "../lib-src/header-substitutes/allegro.h"
|
||||
|
||||
|
||||
NoteTrackAffordanceControls::NoteTrackAffordanceControls(const std::shared_ptr<Track>& pTrack)
|
||||
: CommonTrackCell(pTrack)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
std::vector<UIHandlePtr> NoteTrackAffordanceControls::HitTest(const TrackPanelMouseState& state, const AudacityProject* pProject)
|
||||
{
|
||||
std::vector<UIHandlePtr> results;
|
||||
|
||||
auto track = FindTrack();
|
||||
const auto nt = std::static_pointer_cast<const NoteTrack>(track->SubstitutePendingChangedTrack());
|
||||
|
||||
const auto rect = state.rect;
|
||||
|
||||
auto& zoomInfo = ViewInfo::Get(*pProject);
|
||||
auto left = zoomInfo.TimeToPosition(nt->GetOffset(), rect.x);
|
||||
auto right = zoomInfo.TimeToPosition(nt->GetOffset() + nt->GetSeq().get_real_dur(), rect.x);
|
||||
auto headerRect = wxRect(left, rect.y, right - left, rect.height);
|
||||
|
||||
auto px = state.state.m_x;
|
||||
auto py = state.state.m_y;
|
||||
|
||||
if (px >= headerRect.GetLeft() && px <= headerRect.GetRight() &&
|
||||
py >= headerRect.GetTop() && py <= headerRect.GetBottom())
|
||||
{
|
||||
results.push_back(AffordanceHandle::HitAnywhere(mAffordanceHandle, track));
|
||||
}
|
||||
|
||||
return results;
|
||||
}
|
||||
|
||||
void NoteTrackAffordanceControls::Draw(TrackPanelDrawingContext& context, const wxRect& rect, unsigned iPass)
|
||||
{
|
||||
if (iPass == TrackArtist::PassBackground) {
|
||||
const auto nt = std::static_pointer_cast<const NoteTrack>(FindTrack()->SubstitutePendingChangedTrack());
|
||||
const auto artist = TrackArtist::Get(context);
|
||||
|
||||
TrackArt::DrawBackgroundWithSelection(context, rect, nt.get(), AColor::labelSelectedBrush, AColor::labelUnselectedBrush);
|
||||
|
||||
const auto& zoomInfo = *artist->pZoomInfo;
|
||||
auto left = zoomInfo.TimeToPosition(nt->GetOffset(), rect.x);
|
||||
auto right = zoomInfo.TimeToPosition(nt->GetOffset() + nt->GetSeq().get_real_dur(), rect.x);
|
||||
auto clipRect = wxRect(left, rect.y, right - left + 1, rect.height);
|
||||
|
||||
auto px = context.lastState.m_x;
|
||||
auto py = context.lastState.m_y;
|
||||
|
||||
auto selected = IsSelected();
|
||||
auto highlight = selected ||
|
||||
(px >= clipRect.GetLeft() && px <= clipRect.GetRight() &&
|
||||
py >= clipRect.GetTop() && py <= clipRect.GetBottom());
|
||||
|
||||
context.dc.SetClippingRegion(rect);
|
||||
TrackArt::DrawClipAffordance(context.dc, clipRect, highlight, selected);
|
||||
context.dc.DestroyClippingRegion();
|
||||
}
|
||||
}
|
||||
|
||||
bool NoteTrackAffordanceControls::IsSelected() const
|
||||
{
|
||||
if (auto handle = mAffordanceHandle.lock())
|
||||
{
|
||||
return handle->Clicked();
|
||||
}
|
||||
return false;
|
||||
}
|
@ -0,0 +1,28 @@
|
||||
/*!********************************************************************
|
||||
*
|
||||
Audacity: A Digital Audio Editor
|
||||
|
||||
NoteTrackAffordanceControls.h
|
||||
|
||||
Vitaly Sverchinsky
|
||||
|
||||
**********************************************************************/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "../../../ui/CommonTrackPanelCell.h"
|
||||
|
||||
class AffordanceHandle;
|
||||
|
||||
class AUDACITY_DLL_API NoteTrackAffordanceControls : public CommonTrackCell
|
||||
{
|
||||
std::weak_ptr<AffordanceHandle> mAffordanceHandle;
|
||||
public:
|
||||
NoteTrackAffordanceControls(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;
|
||||
|
||||
bool IsSelected() const;
|
||||
};
|
@ -27,6 +27,7 @@ Paul Licameli split from TrackPanel.cpp
|
||||
#include "../../../../ViewInfo.h"
|
||||
#include "../../../ui/SelectHandle.h"
|
||||
#include "StretchHandle.h"
|
||||
#include "NoteTrackAffordanceControls.h"
|
||||
|
||||
#include <wx/dc.h>
|
||||
|
||||
@ -75,6 +76,11 @@ std::shared_ptr<TrackVRulerControls> NoteTrackView::DoGetVRulerControls()
|
||||
#define TIME_TO_X(t) (zoomInfo.TimeToPosition((t), rect.x))
|
||||
#define X_TO_TIME(xx) (zoomInfo.PositionToTime((xx), rect.x))
|
||||
|
||||
std::shared_ptr<CommonTrackCell> NoteTrackView::DoGetAffordanceControls()
|
||||
{
|
||||
return std::make_shared<NoteTrackAffordanceControls>(DoFindTrack());
|
||||
}
|
||||
|
||||
namespace {
|
||||
|
||||
/*
|
||||
@ -352,7 +358,8 @@ window and draw out-of-bounds notes here instead.
|
||||
void DrawNoteTrack(TrackPanelDrawingContext &context,
|
||||
const NoteTrack *track,
|
||||
const wxRect & rect,
|
||||
bool muted)
|
||||
bool muted,
|
||||
bool selected)
|
||||
{
|
||||
auto &dc = context.dc;
|
||||
const auto artist = TrackArtist::Get( context );
|
||||
@ -378,11 +385,6 @@ void DrawNoteTrack(TrackPanelDrawingContext &context,
|
||||
int numPitches = (rect.height) / data.GetPitchHeight(1);
|
||||
if (numPitches < 0) numPitches = 0; // cannot be negative
|
||||
|
||||
#ifdef EXPERIMENTAL_NOTETRACK_OVERLAY
|
||||
TrackArt::DrawBackgroundWithSelection(context, rect, track,
|
||||
AColor::labelSelectedBrush, AColor::labelUnselectedBrush);
|
||||
#endif
|
||||
|
||||
// Background comes in 4 colors, that are now themed.
|
||||
// 214, 214,214 -- unselected white keys
|
||||
// 192,192,192 -- black keys
|
||||
@ -704,6 +706,14 @@ void DrawNoteTrack(TrackPanelDrawingContext &context,
|
||||
TrackArt::DrawNegativeOffsetTrackArrows( context, rect );
|
||||
}
|
||||
|
||||
//draw clip edges
|
||||
{
|
||||
int left = TIME_TO_X(track->GetOffset());
|
||||
int right = TIME_TO_X(track->GetOffset() + track->GetSeq().get_real_dur());
|
||||
|
||||
TrackArt::DrawClipEdges(dc, wxRect(left, rect.GetTop(), right - left + 1, rect.GetHeight()), selected);
|
||||
}
|
||||
|
||||
dc.DestroyClippingRegion();
|
||||
SonifyEndNoteForeground();
|
||||
}
|
||||
@ -723,7 +733,17 @@ void NoteTrackView::Draw(
|
||||
const auto hasSolo = artist->hasSolo;
|
||||
muted = (hasSolo || nt->GetMute()) && !nt->GetSolo();
|
||||
#endif
|
||||
DrawNoteTrack( context, nt.get(), rect, muted );
|
||||
|
||||
#ifdef EXPERIMENTAL_NOTETRACK_OVERLAY
|
||||
TrackArt::DrawBackgroundWithSelection(context, rect, nt.get(), AColor::labelSelectedBrush, AColor::labelUnselectedBrush);
|
||||
#endif
|
||||
bool selected{ false };
|
||||
if (auto affordance = std::dynamic_pointer_cast<NoteTrackAffordanceControls>(GetAffordanceControls()))
|
||||
{
|
||||
selected = affordance->IsSelected();
|
||||
}
|
||||
|
||||
DrawNoteTrack(context, nt.get(), rect, muted, selected);
|
||||
}
|
||||
CommonTrackView::Draw( context, rect, iPass );
|
||||
}
|
||||
|
@ -23,9 +23,10 @@ public:
|
||||
NoteTrackView( const std::shared_ptr<Track> &pTrack );
|
||||
~NoteTrackView() override;
|
||||
|
||||
std::shared_ptr<TrackVRulerControls> DoGetVRulerControls() override;
|
||||
|
||||
private:
|
||||
std::shared_ptr<TrackVRulerControls> DoGetVRulerControls() override;
|
||||
std::shared_ptr<CommonTrackCell> DoGetAffordanceControls() override;
|
||||
|
||||
std::vector<UIHandlePtr> DetailedHitTest
|
||||
(const TrackPanelMouseState &state,
|
||||
const AudacityProject *pProject, int currentTool, bool bMultiTool)
|
||||
|
@ -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{
|
||||
|
@ -38,6 +38,7 @@ private:
|
||||
|
||||
static void DoDraw( TrackPanelDrawingContext &context,
|
||||
const WaveTrack *track,
|
||||
const WaveClip* selectedClip,
|
||||
const wxRect & rect );
|
||||
|
||||
std::vector<UIHandlePtr> DetailedHitTest(
|
||||
|
@ -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 {};
|
||||
}
|
@ -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;
|
||||
};
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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{
|
||||
|
@ -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);
|
||||
|
||||
|
116
src/tracks/ui/AffordanceHandle.cpp
Normal file
116
src/tracks/ui/AffordanceHandle.cpp
Normal file
@ -0,0 +1,116 @@
|
||||
/*!********************************************************************
|
||||
*
|
||||
Audacity: A Digital Audio Editor
|
||||
|
||||
AffordanceHandle.cpp
|
||||
|
||||
Vitaly Sverchinsky
|
||||
|
||||
**********************************************************************/
|
||||
|
||||
#include "AffordanceHandle.h"
|
||||
|
||||
#include "../../HitTestResult.h"
|
||||
#include "../../ProjectAudioIO.h"
|
||||
#include "../../RefreshCode.h"
|
||||
#include "../../ViewInfo.h"
|
||||
#include "../../SelectionState.h"
|
||||
#include "../../ProjectSettings.h"
|
||||
#include "../../TrackPanelMouseEvent.h"
|
||||
#include "../../WaveClip.h"
|
||||
#include "../../ProjectHistory.h"
|
||||
#include "../../Track.h"
|
||||
#include "../../WaveTrack.h"
|
||||
#include "../../../images/Cursors.h"
|
||||
|
||||
UIHandlePtr AffordanceHandle::HitAnywhere(std::weak_ptr<AffordanceHandle>& holder, const std::shared_ptr<Track>& pTrack)
|
||||
{
|
||||
auto result = std::make_shared<AffordanceHandle>(pTrack);
|
||||
result = AssignUIHandlePtr(holder, result);
|
||||
return result;
|
||||
}
|
||||
|
||||
HitTestPreview AffordanceHandle::HitPreview(const AudacityProject*, bool unsafe, bool moving)
|
||||
{
|
||||
static auto disabledCursor =
|
||||
MakeCursor(wxCURSOR_NO_ENTRY, DisabledCursorXpm, 16, 16);
|
||||
static auto handOpenCursor =
|
||||
MakeCursor(wxCURSOR_HAND, RearrangeCursorXpm, 16, 16);
|
||||
static auto handClosedCursor =
|
||||
MakeCursor(wxCURSOR_HAND, RearrangingCursorXpm, 16, 16);
|
||||
// i18n-hint Appears on hovering mouse over clip affordance
|
||||
auto message = XO("Click and drag to move a clip in time, or click to select");
|
||||
|
||||
if (unsafe)
|
||||
return { message, &*disabledCursor };
|
||||
return {
|
||||
message,
|
||||
(moving
|
||||
? &*handClosedCursor
|
||||
: &*handOpenCursor)
|
||||
};
|
||||
}
|
||||
|
||||
HitTestPreview AffordanceHandle::Preview(const TrackPanelMouseState& mouseState, AudacityProject* pProject)
|
||||
{
|
||||
const bool unsafe = ProjectAudioIO::Get(*pProject).IsAudioActive();
|
||||
return HitPreview(pProject, unsafe, Clicked());
|
||||
}
|
||||
|
||||
AffordanceHandle::AffordanceHandle(const std::shared_ptr<Track>& track)
|
||||
: TimeShiftHandle(track, false)
|
||||
{
|
||||
SetChangeHighlight(RefreshCode::RefreshCell | RefreshCode::RefreshLatestCell);
|
||||
}
|
||||
|
||||
UIHandle::Result AffordanceHandle::Click(const TrackPanelMouseEvent& evt, AudacityProject* pProject)
|
||||
{
|
||||
auto result = TimeShiftHandle::Click(evt, pProject);
|
||||
return result | RefreshCode::RefreshCell;
|
||||
}
|
||||
|
||||
UIHandle::Result AffordanceHandle::Release(const TrackPanelMouseEvent& event, AudacityProject* pProject, wxWindow* pParent)
|
||||
{
|
||||
auto result = TimeShiftHandle::Release(event, pProject, pParent);
|
||||
//Clip was not moved
|
||||
if (!TimeShiftHandle::WasMoved())
|
||||
{
|
||||
//almost the same behaviour as provided by SelectHandle
|
||||
auto& viewInfo = ViewInfo::Get(*pProject);
|
||||
const auto& settings = ProjectSettings::Get(*pProject);
|
||||
|
||||
const auto sTrack = TrackList::Get(*pProject).Lock<Track>(GetTrack());
|
||||
const auto pTrack = sTrack.get();
|
||||
|
||||
auto& selectionState = SelectionState::Get(*pProject);
|
||||
|
||||
auto& trackList = TrackList::Get(*pProject);
|
||||
|
||||
// Deselect all other tracks and select this one.
|
||||
selectionState.SelectNone(trackList);
|
||||
selectionState.SelectTrack(*pTrack, true, true);
|
||||
|
||||
pTrack->TypeSwitch(
|
||||
[&](WaveTrack* wt)
|
||||
{
|
||||
auto time = viewInfo.PositionToTime(event.event.m_x, event.rect.x);
|
||||
WaveClip* const selectedClip = wt->GetClipAtTime(time);
|
||||
if (selectedClip) {
|
||||
viewInfo.selectedRegion.setTimes(
|
||||
selectedClip->GetOffset(), selectedClip->GetEndTime());
|
||||
}
|
||||
},
|
||||
[&](Track* track)
|
||||
{
|
||||
// Default behavior: select whole track
|
||||
SelectionState::SelectTrackLength(viewInfo, *track, settings.IsSyncLocked());
|
||||
}
|
||||
);
|
||||
|
||||
ProjectHistory::Get(*pProject).ModifyState(false);
|
||||
|
||||
// Do not start a drag
|
||||
result |= RefreshCode::RefreshAll | RefreshCode::Cancelled;
|
||||
}
|
||||
return result;
|
||||
}
|
28
src/tracks/ui/AffordanceHandle.h
Normal file
28
src/tracks/ui/AffordanceHandle.h
Normal file
@ -0,0 +1,28 @@
|
||||
/*!********************************************************************
|
||||
*
|
||||
Audacity: A Digital Audio Editor
|
||||
|
||||
AffordanceHandle.h
|
||||
|
||||
Vitaly Sverchinsky
|
||||
|
||||
**********************************************************************/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "TimeShiftHandle.h"
|
||||
|
||||
class AUDACITY_DLL_API AffordanceHandle : public TimeShiftHandle
|
||||
{
|
||||
static HitTestPreview HitPreview(const AudacityProject*, bool unsafe, bool moving);
|
||||
public:
|
||||
|
||||
static UIHandlePtr HitAnywhere(std::weak_ptr<AffordanceHandle>& holder, const std::shared_ptr<Track>& pTrack);
|
||||
|
||||
HitTestPreview Preview(const TrackPanelMouseState& mouseState, AudacityProject* pProject) override;
|
||||
|
||||
AffordanceHandle(const std::shared_ptr<Track>& track);
|
||||
|
||||
Result Click(const TrackPanelMouseEvent& evt, AudacityProject* pProject) override;
|
||||
Result Release(const TrackPanelMouseEvent& event, AudacityProject* pProject, wxWindow* pParent) override;
|
||||
};
|
@ -100,24 +100,7 @@ void PlayIndicatorOverlayBase::Draw(OverlayPanel &panel, wxDC &dc)
|
||||
if(auto tp = dynamic_cast<TrackPanel*>(&panel)) {
|
||||
wxASSERT(mIsMaster);
|
||||
|
||||
// Draw indicator in all visible tracks
|
||||
tp->VisitCells( [&]( const wxRect &rect, TrackPanelCell &cell ) {
|
||||
const auto pTrackView = dynamic_cast<TrackView*>(&cell);
|
||||
if (pTrackView) pTrackView->FindTrack()->TypeSwitch(
|
||||
[](LabelTrack *) {
|
||||
// Don't draw the indicator in label tracks
|
||||
},
|
||||
[&](Track *) {
|
||||
// Draw the NEW indicator in its NEW location
|
||||
// AColor::Line includes both endpoints so use GetBottom()
|
||||
AColor::Line(dc,
|
||||
mLastIndicatorX,
|
||||
rect.GetTop(),
|
||||
mLastIndicatorX,
|
||||
rect.GetBottom());
|
||||
}
|
||||
);
|
||||
} );
|
||||
AColor::Line(dc, mLastIndicatorX, tp->GetRect().GetTop(), mLastIndicatorX, tp->GetRect().GetBottom());
|
||||
}
|
||||
else if(auto ruler = dynamic_cast<AdornedRulerPanel*>(&panel)) {
|
||||
wxASSERT(!mIsMaster);
|
||||
|
@ -34,6 +34,21 @@ TimeShiftHandle::TimeShiftHandle
|
||||
mClipMoveState.mCapturedTrack = pTrack;
|
||||
}
|
||||
|
||||
std::shared_ptr<Track> TimeShiftHandle::GetTrack() const
|
||||
{
|
||||
return mClipMoveState.mCapturedTrack;
|
||||
}
|
||||
|
||||
bool TimeShiftHandle::WasMoved() const
|
||||
{
|
||||
return mDidSlideVertically || (mClipMoveState.initialized && mClipMoveState.wasMoved);
|
||||
}
|
||||
|
||||
bool TimeShiftHandle::Clicked() const
|
||||
{
|
||||
return mClipMoveState.initialized;
|
||||
}
|
||||
|
||||
void TimeShiftHandle::Enter(bool, AudacityProject *)
|
||||
{
|
||||
#ifdef EXPERIMENTAL_TRACK_PANEL_HIGHLIGHTING
|
||||
@ -275,6 +290,8 @@ void ClipMoveState::Init(
|
||||
{
|
||||
shifters.clear();
|
||||
|
||||
initialized = true;
|
||||
|
||||
auto &state = *this;
|
||||
state.mCapturedTrack = capturedTrack.SharedPointer();
|
||||
|
||||
@ -427,6 +444,9 @@ double ClipMoveState::DoSlideHorizontal( double desiredSlideAmount )
|
||||
if ( desiredSlideAmount != 0.0 )
|
||||
state.DoHorizontalOffset( desiredSlideAmount );
|
||||
|
||||
//attempt to move a clip is counted to
|
||||
wasMoved = true;
|
||||
|
||||
return (state.hSlideAmount = desiredSlideAmount);
|
||||
}
|
||||
|
||||
|
@ -235,7 +235,9 @@ struct AUDACITY_DLL_API ClipMoveState {
|
||||
|
||||
std::shared_ptr<Track> mCapturedTrack;
|
||||
|
||||
bool initialized{ false };
|
||||
bool movingSelection {};
|
||||
bool wasMoved{ false };
|
||||
double hSlideAmount {};
|
||||
ShifterMap shifters;
|
||||
wxInt64 snapLeft { -1 }, snapRight { -1 };
|
||||
@ -244,6 +246,8 @@ struct AUDACITY_DLL_API ClipMoveState {
|
||||
|
||||
void clear()
|
||||
{
|
||||
initialized = false;
|
||||
wasMoved = false;
|
||||
movingSelection = false;
|
||||
hSlideAmount = 0;
|
||||
shifters.clear();
|
||||
@ -252,7 +256,7 @@ struct AUDACITY_DLL_API ClipMoveState {
|
||||
}
|
||||
};
|
||||
|
||||
class AUDACITY_DLL_API TimeShiftHandle final : public UIHandle
|
||||
class AUDACITY_DLL_API TimeShiftHandle : public UIHandle
|
||||
{
|
||||
TimeShiftHandle(const TimeShiftHandle&) = delete;
|
||||
static HitTestPreview HitPreview
|
||||
@ -265,7 +269,6 @@ public:
|
||||
TimeShiftHandle &operator=(TimeShiftHandle&&) = default;
|
||||
|
||||
bool IsGripHit() const { return mGripHit; }
|
||||
std::shared_ptr<Track> GetTrack() const = delete;
|
||||
|
||||
// Try to move clips from one track to another, before also moving
|
||||
// by some horizontal amount, which may be slightly adjusted to fit the
|
||||
@ -305,6 +308,12 @@ public:
|
||||
|
||||
bool StopsOnKeystroke() override { return true; }
|
||||
|
||||
bool Clicked() const;
|
||||
|
||||
protected:
|
||||
std::shared_ptr<Track> GetTrack() const;
|
||||
//There were attempt to move clip/track horizontally, or to move it vertically
|
||||
bool WasMoved() const;
|
||||
private:
|
||||
// TrackPanelDrawable implementation
|
||||
void Draw(
|
||||
|
@ -141,6 +141,13 @@ std::shared_ptr<const TrackVRulerControls> TrackView::GetVRulerControls() const
|
||||
return const_cast< TrackView* >( this )->GetVRulerControls();
|
||||
}
|
||||
|
||||
std::shared_ptr<CommonTrackCell> TrackView::GetAffordanceControls()
|
||||
{
|
||||
if (!mpAffordanceCellControl)
|
||||
mpAffordanceCellControl = DoGetAffordanceControls();
|
||||
return mpAffordanceCellControl;
|
||||
}
|
||||
|
||||
void TrackView::DoSetY(int y)
|
||||
{
|
||||
mY = y;
|
||||
@ -165,6 +172,11 @@ void TrackView::DoSetHeight(int h)
|
||||
mHeight = h;
|
||||
}
|
||||
|
||||
std::shared_ptr<CommonTrackCell> TrackView::DoGetAffordanceControls()
|
||||
{
|
||||
return {};
|
||||
}
|
||||
|
||||
namespace {
|
||||
|
||||
// Attach an object to each project. It receives track list events and updates
|
||||
|
@ -62,6 +62,9 @@ public:
|
||||
std::shared_ptr<TrackVRulerControls> GetVRulerControls();
|
||||
std::shared_ptr<const TrackVRulerControls> GetVRulerControls() const;
|
||||
|
||||
// by default returns nullptr, meaning that track has no drag controls area
|
||||
std::shared_ptr<CommonTrackCell> GetAffordanceControls();
|
||||
|
||||
|
||||
void WriteXMLAttributes( XMLWriter & ) const override;
|
||||
bool HandleXMLAttribute( const wxChar *attr, const wxChar *value ) override;
|
||||
@ -88,8 +91,11 @@ protected:
|
||||
// Private factory to make appropriate object; class TrackView handles
|
||||
// memory management thereafter
|
||||
virtual std::shared_ptr<TrackVRulerControls> DoGetVRulerControls() = 0;
|
||||
// May return nullptr (which is default) if track does not need affordance area
|
||||
virtual std::shared_ptr<CommonTrackCell> DoGetAffordanceControls();
|
||||
|
||||
std::shared_ptr<TrackVRulerControls> mpVRulerControls;
|
||||
std::shared_ptr<CommonTrackCell> mpAffordanceCellControl;
|
||||
|
||||
private:
|
||||
bool mMinimized{ false };
|
||||
|
Loading…
x
Reference in New Issue
Block a user