mirror of
https://github.com/cookiengineer/audacity
synced 2025-05-02 08:39:46 +02:00
TrackPanel, AdornedRulerPanel each define subdivision in one place...
... excepting the duplication still remaining in TrackPanel::FindTrackRect. Subdivision of the panel's area is defined recusively using helper classes that each report a refinement of a sub-rectangle on one of the two axes until what remains is a rectangle occupied by one cell only. TrackPanelCellIterator, which iterated over TrackPanel's subdivision by other means, is replaced by this. CellularPanel thus requires only one virtual function definition for subdivision, not two as before, and from that figures out in a generalized way how to find a cell given a point, or a rectangle given a cell, or an iteration over all cells within visible bounds. In future, a rewrite of drawing may invoke virtual functions not only on the cell objects, but also on the groupings of them. For instance to draw the focus rectangle of a stereo track, which surrounds several of the cells -- the control panel, the channels, and the resizer between. So it's good to reify such groupings of cells as objects.
This commit is contained in:
commit
b7e1cc09a5
@ -205,7 +205,6 @@ src/TrackPanel.h
|
||||
src/TrackPanelAx.cpp
|
||||
src/TrackPanelAx.h
|
||||
src/TrackPanelCell.h
|
||||
src/TrackPanelCellIterator.h
|
||||
src/TrackPanelDrawingContext.h
|
||||
src/TrackPanelListener.h
|
||||
src/TrackPanelMouseEvent.h
|
||||
|
@ -3167,7 +3167,6 @@
|
||||
5E73966F1DAFDB9D00BA0A4D /* SelectHandle.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = SelectHandle.cpp; sourceTree = "<group>"; };
|
||||
5E7396701DAFDB9D00BA0A4D /* SelectHandle.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SelectHandle.h; sourceTree = "<group>"; };
|
||||
5E74D2D91CC4427B00D88B0B /* TrackPanelCell.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = TrackPanelCell.h; sourceTree = "<group>"; };
|
||||
5E74D2DA1CC4427B00D88B0B /* TrackPanelCellIterator.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = TrackPanelCellIterator.h; sourceTree = "<group>"; };
|
||||
5E74D2DD1CC4429700D88B0B /* EditCursorOverlay.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = EditCursorOverlay.cpp; sourceTree = "<group>"; };
|
||||
5E74D2DE1CC4429700D88B0B /* EditCursorOverlay.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = EditCursorOverlay.h; sourceTree = "<group>"; };
|
||||
5E74D2DF1CC4429700D88B0B /* PlayIndicatorOverlay.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = PlayIndicatorOverlay.cpp; sourceTree = "<group>"; };
|
||||
@ -4273,7 +4272,6 @@
|
||||
1790B0ED09883BFD008A330A /* TrackPanel.h */,
|
||||
1790B0EF09883BFD008A330A /* TrackPanelAx.h */,
|
||||
5E74D2D91CC4427B00D88B0B /* TrackPanelCell.h */,
|
||||
5E74D2DA1CC4427B00D88B0B /* TrackPanelCellIterator.h */,
|
||||
5E52335F1EFDD57D001E4BB8 /* TrackPanelDrawingContext.h */,
|
||||
2803C8B619F35AA000278526 /* TrackPanelListener.h */,
|
||||
5E15123A1DB000C000702E29 /* TrackPanelMouseEvent.h */,
|
||||
|
@ -33,7 +33,6 @@
|
||||
#include "RefreshCode.h"
|
||||
#include "Snap.h"
|
||||
#include "TrackPanel.h"
|
||||
#include "TrackPanelCellIterator.h"
|
||||
#include "TrackPanelMouseEvent.h"
|
||||
#include "UIHandle.h"
|
||||
#include "prefs/TracksBehaviorsPrefs.h"
|
||||
@ -328,20 +327,19 @@ void AdornedRulerPanel::QuickPlayIndicatorOverlay::Draw(
|
||||
;
|
||||
|
||||
// Draw indicator in all visible tracks
|
||||
for ( const auto &data : static_cast<TrackPanel&>(panel).Cells() )
|
||||
{
|
||||
Track *const pTrack = dynamic_cast<Track*>(data.first.get());
|
||||
if (!pTrack)
|
||||
continue;
|
||||
const wxRect &rect = data.second;
|
||||
static_cast<TrackPanel&>(panel)
|
||||
.VisitCells( [&]( const wxRect &rect, TrackPanelCell &cell ) {
|
||||
const auto pTrack = dynamic_cast<Track*>(&cell);
|
||||
if (!pTrack)
|
||||
return;
|
||||
|
||||
// Draw the NEW indicator in its NEW location
|
||||
AColor::Line(dc,
|
||||
mOldQPIndicatorPos,
|
||||
rect.GetTop(),
|
||||
mOldQPIndicatorPos,
|
||||
rect.GetBottom());
|
||||
}
|
||||
// Draw the NEW indicator in its NEW location
|
||||
AColor::Line(dc,
|
||||
mOldQPIndicatorPos,
|
||||
rect.GetTop(),
|
||||
mOldQPIndicatorPos,
|
||||
rect.GetBottom());
|
||||
} );
|
||||
}
|
||||
}
|
||||
|
||||
@ -2101,31 +2099,46 @@ void AdornedRulerPanel::GetMaxSize(wxCoord *width, wxCoord *height)
|
||||
mRuler.GetMaxSize(width, height);
|
||||
}
|
||||
|
||||
// Second-level subdivision includes quick-play region and maybe the scrub bar
|
||||
// and also shaves little margins above and below
|
||||
struct AdornedRulerPanel::Subgroup final : TrackPanelGroup {
|
||||
explicit Subgroup( const AdornedRulerPanel &ruler ) : mRuler{ ruler } {}
|
||||
Subdivision Children( const wxRect & ) override
|
||||
{
|
||||
return { Axis::Y, ( mRuler.mShowScrubbing )
|
||||
? Refinement{
|
||||
{ mRuler.mInner.GetTop(), mRuler.mQPCell },
|
||||
{ mRuler.mScrubZone.GetTop(), mRuler.mScrubbingCell },
|
||||
{ mRuler.mScrubZone.GetBottom() + 1, nullptr }
|
||||
}
|
||||
: Refinement{
|
||||
{ mRuler.mInner.GetTop(), mRuler.mQPCell },
|
||||
{ mRuler.mInner.GetBottom() + 1, nullptr }
|
||||
}
|
||||
};
|
||||
}
|
||||
const AdornedRulerPanel &mRuler;
|
||||
};
|
||||
|
||||
// Top-level subdivision shaves little margins off left and right
|
||||
struct AdornedRulerPanel::MainGroup final : TrackPanelGroup {
|
||||
explicit MainGroup( const AdornedRulerPanel &ruler ) : mRuler{ ruler } {}
|
||||
Subdivision Children( const wxRect & ) override
|
||||
{ return { Axis::X, Refinement{
|
||||
// Subgroup is a throwaway object
|
||||
{ mRuler.mInner.GetLeft(), std::make_shared< Subgroup >( mRuler ) },
|
||||
{ mRuler.mInner.GetRight() + 1, nullptr }
|
||||
} }; }
|
||||
const AdornedRulerPanel &mRuler;
|
||||
};
|
||||
|
||||
// CellularPanel implementation
|
||||
auto AdornedRulerPanel::FindCell(int mouseX, int mouseY) -> FoundCell
|
||||
std::shared_ptr<TrackPanelNode> AdornedRulerPanel::Root()
|
||||
{
|
||||
bool mayScrub = mProject->GetScrubber().CanScrub() &&
|
||||
mShowScrubbing;
|
||||
if (mayScrub && mScrubZone.Contains(mouseX, mouseY))
|
||||
return { mScrubbingCell, mScrubZone };
|
||||
|
||||
if (mInner.Contains(mouseX, mouseY))
|
||||
return { mQPCell, mInner };
|
||||
|
||||
return {};
|
||||
// Root is a throwaway object
|
||||
return std::make_shared< MainGroup >( *this );
|
||||
}
|
||||
|
||||
wxRect AdornedRulerPanel::FindRect(const TrackPanelCell &cell)
|
||||
{
|
||||
if (&cell == mScrubbingCell.get())
|
||||
return mScrubZone;
|
||||
if (&cell == mQPCell.get())
|
||||
return mInner;
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
|
||||
AudacityProject * AdornedRulerPanel::GetProject() const
|
||||
{
|
||||
return mProject;
|
||||
|
@ -172,8 +172,10 @@ private:
|
||||
//
|
||||
// CellularPanel implementation
|
||||
//
|
||||
FoundCell FindCell(int mouseX, int mouseY) override;
|
||||
wxRect FindRect(const TrackPanelCell &cell) override;
|
||||
|
||||
// Get the root object defining a recursive subdivision of the panel's
|
||||
// area into cells
|
||||
std::shared_ptr<TrackPanelNode> Root() override;
|
||||
public:
|
||||
AudacityProject * GetProject() const override;
|
||||
private:
|
||||
@ -207,6 +209,10 @@ private:
|
||||
|
||||
class ScrubbingCell;
|
||||
std::shared_ptr<ScrubbingCell> mScrubbingCell;
|
||||
|
||||
// classes implementing subdivision for CellularPanel
|
||||
struct Subgroup;
|
||||
struct MainGroup;
|
||||
};
|
||||
|
||||
#endif //define __AUDACITY_ADORNED_RULER_PANEL__
|
||||
|
@ -860,6 +860,174 @@ void CellularPanel::OnKillFocus(wxFocusEvent & WXUNUSED(event))
|
||||
Refresh( false);
|
||||
}
|
||||
|
||||
// Empty out-of-line default functions to fill Visitor's vtable
|
||||
CellularPanel::Visitor::~Visitor() {}
|
||||
void CellularPanel::Visitor::VisitCell(
|
||||
const wxRect &rect, TrackPanelCell &cell ) {}
|
||||
void CellularPanel::Visitor::BeginGroup(
|
||||
const wxRect &rect, TrackPanelGroup &group ) {}
|
||||
void CellularPanel::Visitor::EndGroup(
|
||||
const wxRect &rect, TrackPanelGroup &group ) {}
|
||||
|
||||
// Public, top-level entry for generalized Visit
|
||||
void CellularPanel::Visit( Visitor &visitor )
|
||||
{
|
||||
Visit( GetClientRect(), Root(), visitor );
|
||||
}
|
||||
|
||||
// Common utility class for the functions that follow
|
||||
namespace {
|
||||
struct Adaptor : CellularPanel::Visitor {
|
||||
using SimpleCellVisitor = CellularPanel::SimpleCellVisitor;
|
||||
using SimpleNodeVisitor = CellularPanel::SimpleNodeVisitor;
|
||||
|
||||
// Visit cells only
|
||||
Adaptor( const SimpleCellVisitor& function_ )
|
||||
: function{ [&](const wxRect &rect, TrackPanelNode &cell) {
|
||||
return function_( rect, static_cast<TrackPanelCell&>(cell) );
|
||||
} }
|
||||
{}
|
||||
|
||||
// Visit cells and groups, each once only, choosing pre- or post- ordering
|
||||
// for the groups
|
||||
Adaptor( const SimpleNodeVisitor &function_, bool pre_ )
|
||||
: function{ function_ }, pre{ pre_ }, post{ ! pre_ } {}
|
||||
|
||||
void VisitCell( const wxRect &rect, TrackPanelCell &cell ) override
|
||||
{ return function( rect, cell ); }
|
||||
void BeginGroup( const wxRect &rect, TrackPanelGroup &group ) override
|
||||
{ if (pre) return function( rect, group ); }
|
||||
void EndGroup( const wxRect &rect, TrackPanelGroup &group ) override
|
||||
{ if (post) return function( rect, group ); }
|
||||
|
||||
SimpleNodeVisitor function;
|
||||
const bool pre{ false }, post{ false };
|
||||
};
|
||||
}
|
||||
|
||||
// Simplified entry points for visits that don't need all the generality of
|
||||
// CellularPanel::Visitor
|
||||
void CellularPanel::VisitCells( const SimpleCellVisitor &visitor )
|
||||
{
|
||||
Adaptor adaptor{ visitor };
|
||||
Visit( adaptor );
|
||||
}
|
||||
|
||||
void CellularPanel::VisitPreorder( const SimpleNodeVisitor &visitor )
|
||||
{
|
||||
Adaptor adaptor{ visitor, true };
|
||||
Visit( adaptor );
|
||||
}
|
||||
|
||||
void CellularPanel::VisitPostorder( const SimpleNodeVisitor &visitor )
|
||||
{
|
||||
Adaptor adaptor{ visitor, false };
|
||||
Visit( adaptor );
|
||||
}
|
||||
|
||||
namespace {
|
||||
wxRect Subdivide(
|
||||
const wxRect &rect, bool divideX,
|
||||
const TrackPanelGroup::Refinement &children,
|
||||
const TrackPanelGroup::Refinement::const_iterator iter)
|
||||
{
|
||||
const auto lowerBound = (divideX ? rect.GetLeft() : rect.GetTop());
|
||||
const auto upperBound = (divideX ? rect.GetRight() : rect.GetBottom());
|
||||
const auto next = iter + 1;
|
||||
const auto end = children.end();
|
||||
const auto nextCoord = ((next == end) ? upperBound : next->first - 1);
|
||||
|
||||
auto lesser = std::max(lowerBound, std::min(upperBound, iter->first));
|
||||
auto greater = std::max(lesser, std::min(upperBound, nextCoord));
|
||||
|
||||
auto result = rect;
|
||||
if (divideX)
|
||||
result.SetLeft(lesser), result.SetRight(greater);
|
||||
else
|
||||
result.SetTop(lesser), result.SetBottom(greater);
|
||||
|
||||
return result;
|
||||
};
|
||||
}
|
||||
|
||||
// Private, recursive implementation function of Visit
|
||||
void CellularPanel::Visit(
|
||||
const wxRect &rect, const std::shared_ptr<TrackPanelNode> &node,
|
||||
Visitor &visitor )
|
||||
{
|
||||
if (auto pCell = dynamic_cast<TrackPanelCell*>(node.get()))
|
||||
visitor.VisitCell( rect, *pCell );
|
||||
else if (auto pGroup = dynamic_cast<TrackPanelGroup*>(node.get())) {
|
||||
visitor.BeginGroup( rect, *pGroup );
|
||||
|
||||
// Recur on children
|
||||
const auto results = pGroup->Children( rect );
|
||||
const bool divideX = results.first == TrackPanelGroup::Axis::X;
|
||||
const auto &children = results.second;
|
||||
const auto begin = children.begin(), end = children.end();
|
||||
for (auto iter = begin; iter != end; ++iter)
|
||||
Visit(
|
||||
Subdivide(rect, divideX, children, iter), iter->second, visitor );
|
||||
|
||||
visitor.EndGroup( rect, *pGroup );
|
||||
}
|
||||
else
|
||||
return;
|
||||
}
|
||||
|
||||
auto CellularPanel::FindCell(int mouseX, int mouseY) -> FoundCell
|
||||
{
|
||||
auto rect = this->GetClientRect();
|
||||
auto node = Root();
|
||||
while (node) {
|
||||
if ( auto pCell = std::dynamic_pointer_cast< TrackPanelCell >( node ) )
|
||||
// Found the bottom of the hierarchy
|
||||
return { pCell, rect };
|
||||
else if ( auto pGroup = dynamic_cast< TrackPanelGroup* >( node.get() ) ) {
|
||||
// Ask node for its subdivision
|
||||
const auto results = pGroup->Children( rect );
|
||||
const bool divideX = results.first == TrackPanelGroup::Axis::X;
|
||||
const auto &children = results.second;
|
||||
|
||||
// Find the correct child
|
||||
const auto begin = children.begin(), end = children.end();
|
||||
auto iter = std::upper_bound( begin, end,
|
||||
(divideX ? mouseX : mouseY),
|
||||
[&]( wxCoord coord, const TrackPanelGroup::Child &child ) {
|
||||
return coord < child.first;
|
||||
}
|
||||
);
|
||||
if (iter == begin)
|
||||
break;
|
||||
--iter;
|
||||
|
||||
// Descend the hierarchy of nodes
|
||||
rect = Subdivide(rect, divideX, children, iter);
|
||||
node = iter->second;
|
||||
}
|
||||
else
|
||||
// Nulls in the array of children are allowed, to define a void with
|
||||
// no cell
|
||||
break;
|
||||
}
|
||||
|
||||
return { {}, {} };
|
||||
}
|
||||
|
||||
wxRect CellularPanel::FindRect( const TrackPanelCell &cell )
|
||||
{
|
||||
wxRect result;
|
||||
|
||||
struct Stop{};
|
||||
try { VisitCells( [&]( const wxRect &rect, TrackPanelCell &visited ) {
|
||||
if ( &visited == &cell )
|
||||
result = rect, throw Stop{};
|
||||
} ); }
|
||||
catch ( const Stop& ) {}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
UIHandlePtr CellularPanel::Target()
|
||||
{
|
||||
auto &state = *mState;
|
||||
|
@ -18,6 +18,8 @@ class ViewInfo;
|
||||
class AudacityProject;
|
||||
|
||||
class TrackPanelCell;
|
||||
class TrackPanelGroup;
|
||||
class TrackPanelNode;
|
||||
struct TrackPanelMouseEvent;
|
||||
struct TrackPanelMouseState;
|
||||
|
||||
@ -42,13 +44,32 @@ public:
|
||||
|
||||
virtual AudacityProject *GetProject() const = 0;
|
||||
|
||||
// Find track info by coordinate
|
||||
struct FoundCell {
|
||||
std::shared_ptr<TrackPanelCell> pCell;
|
||||
wxRect rect;
|
||||
// Get the root object defining a recursive subdivision of the panel's
|
||||
// area into cells
|
||||
virtual std::shared_ptr<TrackPanelNode> Root() = 0;
|
||||
|
||||
// Structure and functions for generalized visitation of the subdivision
|
||||
struct Visitor {
|
||||
virtual ~Visitor();
|
||||
virtual void VisitCell( const wxRect &rect, TrackPanelCell &cell );
|
||||
virtual void BeginGroup( const wxRect &rect, TrackPanelGroup &group );
|
||||
virtual void EndGroup( const wxRect &rect, TrackPanelGroup &group );
|
||||
};
|
||||
virtual FoundCell FindCell(int mouseX, int mouseY) = 0;
|
||||
virtual wxRect FindRect(const TrackPanelCell &cell) = 0;
|
||||
|
||||
// Most general visit
|
||||
void Visit( Visitor &visitor );
|
||||
|
||||
// Easier visit when you care only about cells
|
||||
using SimpleCellVisitor =
|
||||
std::function< void( const wxRect &rect, TrackPanelCell &cell ) >;
|
||||
void VisitCells( const SimpleCellVisitor &visitor );
|
||||
|
||||
// Easier visits when you want to visit each node once only
|
||||
using SimpleNodeVisitor =
|
||||
std::function< void( const wxRect &rect, TrackPanelNode &node ) >;
|
||||
void VisitPreorder( const SimpleNodeVisitor &visitor );
|
||||
void VisitPostorder( const SimpleNodeVisitor &visitor );
|
||||
|
||||
virtual TrackPanelCell *GetFocusedCell() = 0;
|
||||
virtual void SetFocusedCell() = 0;
|
||||
|
||||
@ -63,6 +84,19 @@ public:
|
||||
virtual bool TakesFocus() const = 0;
|
||||
|
||||
public:
|
||||
// Find cell by coordinate
|
||||
struct FoundCell {
|
||||
std::shared_ptr< TrackPanelCell > pCell;
|
||||
wxRect rect;
|
||||
};
|
||||
|
||||
FoundCell FindCell(int mouseX, int mouseY);
|
||||
|
||||
// Search the tree of subdivisions of the panel area for the given cell.
|
||||
// If more than one sub-area is associated with the same cell object, it
|
||||
// is not specified which rectangle is returned.
|
||||
wxRect FindRect(const TrackPanelCell &cell);
|
||||
|
||||
UIHandlePtr Target();
|
||||
|
||||
std::shared_ptr<TrackPanelCell> LastCell() const;
|
||||
@ -80,6 +114,10 @@ protected:
|
||||
void ClearTargets();
|
||||
|
||||
private:
|
||||
void Visit(
|
||||
const wxRect &rect, const std::shared_ptr<TrackPanelNode> &node,
|
||||
Visitor &visitor );
|
||||
|
||||
bool HasRotation();
|
||||
bool ChangeTarget(bool forward, bool cycle);
|
||||
|
||||
|
@ -251,7 +251,6 @@ audacity_SOURCES = \
|
||||
TrackPanelAx.cpp \
|
||||
TrackPanelAx.h \
|
||||
TrackPanelCell.h \
|
||||
TrackPanelCellIterator.h \
|
||||
TrackPanelDrawingContext.h \
|
||||
TrackPanelListener.h \
|
||||
TrackPanelMouseEvent.h \
|
||||
|
@ -330,12 +330,12 @@ am__audacity_SOURCES_DIST = BlockFile.cpp BlockFile.h DirManager.cpp \
|
||||
TimerRecordDialog.cpp TimerRecordDialog.h TimeTrack.cpp \
|
||||
TimeTrack.h Track.cpp Track.h TrackArtist.cpp TrackArtist.h \
|
||||
TrackPanel.cpp TrackPanel.h TrackPanelAx.cpp TrackPanelAx.h \
|
||||
TrackPanelCell.h TrackPanelCellIterator.h \
|
||||
TrackPanelDrawingContext.h TrackPanelListener.h \
|
||||
TrackPanelMouseEvent.h TrackPanelResizeHandle.cpp \
|
||||
TrackPanelResizeHandle.h TrackPanelResizerCell.cpp \
|
||||
TrackPanelResizerCell.h TranslatableStringArray.h UIHandle.h \
|
||||
UIHandle.cpp UndoManager.cpp UndoManager.h UserException.cpp \
|
||||
TrackPanelCell.h TrackPanelDrawingContext.h \
|
||||
TrackPanelListener.h TrackPanelMouseEvent.h \
|
||||
TrackPanelResizeHandle.cpp TrackPanelResizeHandle.h \
|
||||
TrackPanelResizerCell.cpp TrackPanelResizerCell.h \
|
||||
TranslatableStringArray.h UIHandle.h UIHandle.cpp \
|
||||
UndoManager.cpp UndoManager.h UserException.cpp \
|
||||
UserException.h ViewInfo.cpp ViewInfo.h VoiceKey.cpp \
|
||||
VoiceKey.h WaveClip.cpp WaveClip.h WaveTrack.cpp WaveTrack.h \
|
||||
WaveTrackLocation.h WrappedType.cpp WrappedType.h \
|
||||
@ -1378,12 +1378,12 @@ audacity_SOURCES = $(libaudacity_la_SOURCES) AboutDialog.cpp \
|
||||
TimerRecordDialog.cpp TimerRecordDialog.h TimeTrack.cpp \
|
||||
TimeTrack.h Track.cpp Track.h TrackArtist.cpp TrackArtist.h \
|
||||
TrackPanel.cpp TrackPanel.h TrackPanelAx.cpp TrackPanelAx.h \
|
||||
TrackPanelCell.h TrackPanelCellIterator.h \
|
||||
TrackPanelDrawingContext.h TrackPanelListener.h \
|
||||
TrackPanelMouseEvent.h TrackPanelResizeHandle.cpp \
|
||||
TrackPanelResizeHandle.h TrackPanelResizerCell.cpp \
|
||||
TrackPanelResizerCell.h TranslatableStringArray.h UIHandle.h \
|
||||
UIHandle.cpp UndoManager.cpp UndoManager.h UserException.cpp \
|
||||
TrackPanelCell.h TrackPanelDrawingContext.h \
|
||||
TrackPanelListener.h TrackPanelMouseEvent.h \
|
||||
TrackPanelResizeHandle.cpp TrackPanelResizeHandle.h \
|
||||
TrackPanelResizerCell.cpp TrackPanelResizerCell.h \
|
||||
TranslatableStringArray.h UIHandle.h UIHandle.cpp \
|
||||
UndoManager.cpp UndoManager.h UserException.cpp \
|
||||
UserException.h ViewInfo.cpp ViewInfo.h VoiceKey.cpp \
|
||||
VoiceKey.h WaveClip.cpp WaveClip.h WaveTrack.cpp WaveTrack.h \
|
||||
WaveTrackLocation.h WrappedType.cpp WrappedType.h \
|
||||
|
@ -71,7 +71,6 @@ is time to refresh some aspect of the screen.
|
||||
#include "Experimental.h"
|
||||
#include "TrackPanel.h"
|
||||
#include "Project.h"
|
||||
#include "TrackPanelCellIterator.h"
|
||||
#include "TrackPanelMouseEvent.h"
|
||||
#include "TrackPanelResizeHandle.h"
|
||||
//#define DEBUG_DRAW_TIMING 1
|
||||
@ -126,13 +125,13 @@ time, but that width may be adjusted when tracks change their vertical scales.
|
||||
GetLabelWidth() counts columns up to and including the VRuler.
|
||||
GetLeftOffset() is yet one more -- it counts the "one pixel" column.
|
||||
|
||||
FindCell() for label returns a rectangle that OMITS left, top, and bottom
|
||||
Cell for label has a rectangle that OMITS left, top, and bottom
|
||||
margins
|
||||
|
||||
FindCell() for vruler returns a rectangle right of the label,
|
||||
Cell for vruler has a rectangle right of the label,
|
||||
up to and including the One Pixel column, and OMITS top and bottom margins
|
||||
|
||||
FindCell() for track returns a rectangle with x == GetLeftOffset(), and OMITS
|
||||
Cell() for track returns a rectangle with x == GetLeftOffset(), and OMITS
|
||||
right, top, and bottom margins
|
||||
|
||||
+--------------- ... ------ ... --------------------- ... ... -------------+
|
||||
@ -1956,39 +1955,136 @@ void TrackPanel::DrawShadow(const Track * /* t */ , wxDC * dc, const wxRect & re
|
||||
AColor::Line(*dc, right, rect.y, right, rect.y + 1);
|
||||
}
|
||||
|
||||
/// Determines which cell is under the mouse
|
||||
/// @param mouseX - mouse X position.
|
||||
/// @param mouseY - mouse Y position.
|
||||
auto TrackPanel::FindCell(int mouseX, int mouseY) -> FoundCell
|
||||
{
|
||||
auto range = Cells();
|
||||
auto &iter = range.first, &end = range.second;
|
||||
while
|
||||
( iter != end &&
|
||||
!(*iter).second.Contains( mouseX, mouseY ) )
|
||||
++iter;
|
||||
if (iter == end)
|
||||
return {};
|
||||
namespace {
|
||||
|
||||
// Helper classes to implement the subdivision of TrackPanel area for
|
||||
// CellularPanel
|
||||
|
||||
struct EmptyCell final : CommonTrackPanelCell {
|
||||
std::vector< UIHandlePtr > HitTest(
|
||||
const TrackPanelMouseState &, const AudacityProject *) override
|
||||
{ return {}; }
|
||||
virtual std::shared_ptr< Track > FindTrack() override { return {}; }
|
||||
static std::shared_ptr<EmptyCell> Instance()
|
||||
{
|
||||
static auto instance = std::make_shared< EmptyCell >();
|
||||
return instance;
|
||||
}
|
||||
};
|
||||
|
||||
// n channels alternating with n - 1 resizers
|
||||
struct ChannelGroup final : TrackPanelGroup {
|
||||
ChannelGroup( const std::shared_ptr< Track > &pTrack )
|
||||
: mpTrack{ pTrack } {}
|
||||
Subdivision Children( const wxRect &rect ) override
|
||||
{
|
||||
Refinement refinement;
|
||||
|
||||
const auto channels = TrackList::Channels( mpTrack.get() );
|
||||
const auto pLast = *channels.rbegin();
|
||||
wxCoord yy = rect.GetTop();
|
||||
for ( auto channel : channels ) {
|
||||
refinement.emplace_back( yy, Track::Pointer( channel ) );
|
||||
if ( channel != pLast ) {
|
||||
const auto substitute =
|
||||
Track::Pointer( channel )->SubstitutePendingChangedTrack();
|
||||
yy += substitute->GetHeight();
|
||||
refinement.emplace_back(
|
||||
yy - kSeparatorThickness, channel->GetResizer() );
|
||||
}
|
||||
}
|
||||
|
||||
return { Axis::Y, std::move( refinement ) };
|
||||
}
|
||||
std::shared_ptr< Track > mpTrack;
|
||||
};
|
||||
|
||||
// A track control panel left of n channels alternating with n - 1 resizers
|
||||
struct LabeledChannelGroup final : TrackPanelGroup {
|
||||
LabeledChannelGroup(
|
||||
const std::shared_ptr< Track > &pTrack, wxCoord leftOffset )
|
||||
: mpTrack{ pTrack }, mLeftOffset{ leftOffset } {}
|
||||
Subdivision Children( const wxRect &rect ) override
|
||||
{ return { Axis::X, Refinement{
|
||||
{ rect.GetLeft(), mpTrack->GetTrackControl() },
|
||||
{ mLeftOffset, std::make_shared< ChannelGroup >( mpTrack ) }
|
||||
} }; }
|
||||
std::shared_ptr< Track > mpTrack;
|
||||
wxCoord mLeftOffset;
|
||||
};
|
||||
|
||||
// Stacks a label and a single or multi-channel track on a resizer below,
|
||||
// which is associated with the last channel
|
||||
struct ResizingChannelGroup final : TrackPanelGroup {
|
||||
ResizingChannelGroup(
|
||||
const std::shared_ptr< Track > &pTrack, wxCoord leftOffset )
|
||||
: mpTrack{ pTrack }, mLeftOffset{ leftOffset } {}
|
||||
Subdivision Children( const wxRect &rect ) override
|
||||
{ return { Axis::Y, Refinement{
|
||||
{ rect.GetTop(),
|
||||
std::make_shared< LabeledChannelGroup >( mpTrack, mLeftOffset ) },
|
||||
{ rect.GetTop() + rect.GetHeight() - kSeparatorThickness,
|
||||
( *TrackList::Channels( mpTrack.get() ).rbegin() )->GetResizer() }
|
||||
} }; }
|
||||
std::shared_ptr< Track > mpTrack;
|
||||
wxCoord mLeftOffset;
|
||||
};
|
||||
|
||||
// Stacks a dead area at top, the tracks, and the click-to-deselect area below
|
||||
struct Subgroup final : TrackPanelGroup {
|
||||
explicit Subgroup( TrackPanel &panel ) : mPanel{ panel } {}
|
||||
Subdivision Children( const wxRect &rect ) override
|
||||
{
|
||||
wxCoord yy = -mPanel.GetViewInfo()->vpos;
|
||||
Refinement refinement;
|
||||
|
||||
auto &tracks = *mPanel.GetTracks();
|
||||
if ( tracks.Any() )
|
||||
refinement.emplace_back( yy, EmptyCell::Instance() ),
|
||||
yy += kTopMargin;
|
||||
|
||||
for ( const auto leader : tracks.Leaders() ) {
|
||||
wxCoord height = 0;
|
||||
for ( auto channel : TrackList::Channels( leader ) ) {
|
||||
auto substitute =
|
||||
Track::Pointer( channel )->SubstitutePendingChangedTrack();
|
||||
height += substitute->GetHeight();
|
||||
}
|
||||
refinement.emplace_back( yy,
|
||||
std::make_shared< ResizingChannelGroup >(
|
||||
Track::Pointer( leader ), mPanel.GetLeftOffset() )
|
||||
);
|
||||
yy += height;
|
||||
}
|
||||
|
||||
refinement.emplace_back( std::max( 0, yy ), mPanel.GetBackgroundCell() );
|
||||
|
||||
return { Axis::Y, std::move( refinement ) };
|
||||
}
|
||||
TrackPanel &mPanel;
|
||||
};
|
||||
|
||||
// Main group shaves off the left and right margins
|
||||
struct MainGroup final : TrackPanelGroup {
|
||||
explicit MainGroup( TrackPanel &panel ) : mPanel{ panel } {}
|
||||
Subdivision Children( const wxRect &rect ) override
|
||||
{ return { Axis::X, Refinement{
|
||||
{ 0, EmptyCell::Instance() },
|
||||
{ kLeftMargin, std::make_shared< Subgroup >( mPanel ) },
|
||||
{ rect.GetRight() + 1 - kRightMargin, EmptyCell::Instance() }
|
||||
} }; }
|
||||
TrackPanel &mPanel;
|
||||
};
|
||||
|
||||
auto found = *iter;
|
||||
return {
|
||||
found.first,
|
||||
found.second
|
||||
};
|
||||
}
|
||||
|
||||
wxRect TrackPanel::FindRect( const TrackPanelCell &cell )
|
||||
std::shared_ptr<TrackPanelNode> TrackPanel::Root()
|
||||
{
|
||||
auto range = Cells();
|
||||
auto end = range.second,
|
||||
iter = std::find_if( range.first, end,
|
||||
[&]( const decltype(*end) &pair )
|
||||
{ return pair.first.get() == &cell; }
|
||||
);
|
||||
if (iter == end)
|
||||
return {};
|
||||
else
|
||||
return (*iter).second;
|
||||
// Root and other subgroup objects are throwaways.
|
||||
// They might instead be cached to avoid repeated allocation.
|
||||
// That cache would need invalidation when there is addition, deletion, or
|
||||
// permutation of tracks, or change of width of the vertical rulers.
|
||||
return std::make_shared< MainGroup >( *this );
|
||||
}
|
||||
|
||||
// This finds the rectangle of a given track (including all channels),
|
||||
@ -2537,164 +2633,6 @@ void TrackInfo::UpdatePrefs()
|
||||
} while (textWidth >= allowableWidth);
|
||||
}
|
||||
|
||||
IteratorRange< TrackPanelCellIterator > TrackPanel::Cells()
|
||||
{
|
||||
return {
|
||||
TrackPanelCellIterator( this, true ),
|
||||
TrackPanelCellIterator( this, false )
|
||||
};
|
||||
}
|
||||
|
||||
TrackPanelCellIterator::TrackPanelCellIterator(TrackPanel *trackPanel, bool begin)
|
||||
: mPanel{ trackPanel }
|
||||
, mIter{
|
||||
trackPanel->GetTracks()->Any().begin()
|
||||
.Filter( IsVisibleTrack( trackPanel->GetProject() ) )
|
||||
}
|
||||
{
|
||||
if (begin) {
|
||||
mpTrack = Track::Pointer( *mIter );
|
||||
if (mpTrack)
|
||||
mpCell = mpTrack;
|
||||
else
|
||||
mpCell = trackPanel->GetBackgroundCell();
|
||||
}
|
||||
else
|
||||
mDidBackground = true;
|
||||
|
||||
const auto size = mPanel->GetSize();
|
||||
mRect = { 0, 0, size.x, size.y };
|
||||
UpdateRect();
|
||||
}
|
||||
|
||||
TrackPanelCellIterator &TrackPanelCellIterator::operator++ ()
|
||||
{
|
||||
if ( mpTrack ) {
|
||||
if ( ++ mType == CellType::Background )
|
||||
mType = CellType::Track, mpTrack = Track::Pointer( * ++ mIter );
|
||||
}
|
||||
if ( mpTrack ) {
|
||||
if ( mType == CellType::Label &&
|
||||
!mpTrack->IsLeader() )
|
||||
// Visit label of stereo track only once
|
||||
++mType;
|
||||
switch ( mType ) {
|
||||
case CellType::Track:
|
||||
mpCell = mpTrack;
|
||||
break;
|
||||
case CellType::Label:
|
||||
mpCell = mpTrack->GetTrackControl();
|
||||
break;
|
||||
case CellType::VRuler:
|
||||
mpCell = mpTrack->GetVRulerControl();
|
||||
break;
|
||||
case CellType::Resizer: {
|
||||
mpCell = mpTrack->GetResizer();
|
||||
break;
|
||||
}
|
||||
default:
|
||||
// should not happen
|
||||
mpCell.reset();
|
||||
break;
|
||||
}
|
||||
}
|
||||
else if ( !mDidBackground )
|
||||
mpCell = mPanel->GetBackgroundCell(), mDidBackground = true;
|
||||
else
|
||||
mpCell.reset();
|
||||
|
||||
UpdateRect();
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
TrackPanelCellIterator TrackPanelCellIterator::operator++ (int)
|
||||
{
|
||||
TrackPanelCellIterator copy(*this);
|
||||
++ *this;
|
||||
return copy;
|
||||
}
|
||||
|
||||
auto TrackPanelCellIterator::operator* () const -> value_type
|
||||
{
|
||||
return { mpCell, mRect };
|
||||
}
|
||||
|
||||
void TrackPanelCellIterator::UpdateRect()
|
||||
{
|
||||
const auto size = mPanel->GetSize();
|
||||
if ( mpTrack ) {
|
||||
mRect = {
|
||||
0,
|
||||
mpTrack->GetY() - mPanel->GetViewInfo()->vpos,
|
||||
size.x,
|
||||
mpTrack->GetHeight()
|
||||
};
|
||||
switch ( mType ) {
|
||||
case CellType::Track:
|
||||
mRect.x = mPanel->GetLeftOffset();
|
||||
mRect.width -= (mRect.x + kRightMargin);
|
||||
mRect.y += kTopMargin;
|
||||
mRect.height -= (kBottomMargin + kTopMargin);
|
||||
break;
|
||||
case CellType::Label: {
|
||||
mRect.x = kLeftMargin;
|
||||
mRect.width = kTrackInfoWidth - mRect.x;
|
||||
mRect.y += kTopMargin;
|
||||
mRect.height =
|
||||
TrackList::Channels(mpTrack.get())
|
||||
.sum( &Track::GetHeight );
|
||||
mRect.height -= (kBottomMargin + kTopMargin);
|
||||
break;
|
||||
}
|
||||
case CellType::VRuler:
|
||||
{
|
||||
mRect.x = kTrackInfoWidth;
|
||||
// Right edge of the VRuler is inactive.
|
||||
mRect.width = mPanel->GetLeftOffset() - mRect.x;
|
||||
mRect.y += kTopMargin;
|
||||
mRect.height -= (kBottomMargin + kTopMargin);
|
||||
}
|
||||
break;
|
||||
case CellType::Resizer: {
|
||||
// The resizer region encompasses the bottom margin proper to this
|
||||
// track, plus the top margin of the next track (or, an equally
|
||||
// tall zone below, in case there is no next track)
|
||||
if ( mpTrack.get() ==
|
||||
*TrackList::Channels(mpTrack.get()).rbegin() )
|
||||
// Last channel has a resizer extending farther leftward
|
||||
mRect.x = kLeftMargin;
|
||||
else
|
||||
mRect.x = kTrackInfoWidth;
|
||||
mRect.width -= (mRect.x + kRightMargin);
|
||||
mRect.y += (mRect.height - kBottomMargin);
|
||||
mRect.height = (kBottomMargin + kTopMargin);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
// should not happen
|
||||
break;
|
||||
}
|
||||
}
|
||||
else if ( mpCell ) {
|
||||
// Find a disjoint, maybe empty, rectangle
|
||||
// for the empty space appearing at bottom
|
||||
|
||||
mRect.x = kLeftMargin;
|
||||
mRect.width = size.x - (mRect.x + kRightMargin);
|
||||
|
||||
// Use previous value of the bottom, either the whole area if
|
||||
// there were no tracks, or else the resizer of the last track
|
||||
mRect.y =
|
||||
std::min( size.y,
|
||||
std::max( 0,
|
||||
mRect.y + mRect.height ) );
|
||||
mRect.height = size.y - mRect.y;
|
||||
}
|
||||
else
|
||||
mRect = {};
|
||||
}
|
||||
|
||||
static TrackPanel * TrackPanelFactory(wxWindow * parent,
|
||||
wxWindowID id,
|
||||
const wxPoint & pos,
|
||||
@ -2729,6 +2667,22 @@ TrackPanel *(*TrackPanel::FactoryFunction)(
|
||||
TrackPanelListener * listener,
|
||||
AdornedRulerPanel * ruler) = TrackPanelFactory;
|
||||
|
||||
TrackPanelNode::TrackPanelNode()
|
||||
{
|
||||
}
|
||||
|
||||
TrackPanelNode::~TrackPanelNode()
|
||||
{
|
||||
}
|
||||
|
||||
TrackPanelGroup::TrackPanelGroup()
|
||||
{
|
||||
}
|
||||
|
||||
TrackPanelGroup::~TrackPanelGroup()
|
||||
{
|
||||
}
|
||||
|
||||
TrackPanelCell::~TrackPanelCell()
|
||||
{
|
||||
}
|
||||
|
@ -44,7 +44,6 @@ class ControlToolBar; //Needed because state of controls can affect what gets dr
|
||||
class ToolsToolBar; //Needed because state of controls can affect what gets drawn.
|
||||
|
||||
class TrackPanelAx;
|
||||
class TrackPanelCellIterator;
|
||||
|
||||
class NoteTrack;
|
||||
class WaveTrack;
|
||||
@ -248,8 +247,6 @@ class AUDACITY_DLL_API TrackPanel final : public CellularPanel {
|
||||
|
||||
virtual ~ TrackPanel();
|
||||
|
||||
IteratorRange< TrackPanelCellIterator > Cells();
|
||||
|
||||
void UpdatePrefs();
|
||||
void ApplyUpdatedTheme();
|
||||
|
||||
@ -337,11 +334,9 @@ protected:
|
||||
void MakeParentModifyState(bool bWantsAutoSave); // if true, writes auto-save file. Should set only if you really want the state change restored after
|
||||
// a crash, as it can take many seconds for large (eg. 10 track-hours) projects
|
||||
|
||||
// Find track info by coordinate
|
||||
FoundCell FindCell(int mouseX, int mouseY) override;
|
||||
|
||||
// Find rectangle of the given cell
|
||||
wxRect FindRect(const TrackPanelCell &cell) override;
|
||||
// Get the root object defining a recursive subdivision of the panel's
|
||||
// area into cells
|
||||
std::shared_ptr<TrackPanelNode> Root() override;
|
||||
|
||||
int GetVRulerWidth() const;
|
||||
int GetVRulerOffset() const { return mTrackInfo.GetTrackInfoWidth(); }
|
||||
@ -514,6 +509,7 @@ enum : int {
|
||||
kBottomMargin = kShadowThickness + kBorderThickness,
|
||||
kLeftMargin = kLeftInset + kBorderThickness,
|
||||
kRightMargin = kRightInset + kShadowThickness + kBorderThickness,
|
||||
kSeparatorThickness = kBottomMargin + kTopMargin,
|
||||
};
|
||||
|
||||
enum : int {
|
||||
|
@ -28,9 +28,43 @@ using UIHandlePtr = std::shared_ptr<UIHandle>;
|
||||
|
||||
#include <vector>
|
||||
|
||||
// A subtree in the subdivision of the CellularPanel's area
|
||||
class AUDACITY_DLL_API /* not final */ TrackPanelNode
|
||||
{
|
||||
public:
|
||||
TrackPanelNode();
|
||||
virtual ~TrackPanelNode() = 0;
|
||||
};
|
||||
|
||||
// A non-leaf
|
||||
class AUDACITY_DLL_API TrackPanelGroup /* not final */ : public TrackPanelNode
|
||||
{
|
||||
public:
|
||||
TrackPanelGroup();
|
||||
virtual ~TrackPanelGroup();
|
||||
|
||||
enum class Axis { X, Y };
|
||||
|
||||
// A refinement of a given rectangle partitions it along one of its axes
|
||||
// and associates TrackPanelNodes with the partition.
|
||||
// The sequence of coordinates should be increasing, giving left or top
|
||||
// coordinates of sub-rectangles.
|
||||
// Null pointers are permitted to define empty spaces with no cell object.
|
||||
// If the first coordinate is right of or below the rectangle boundary,
|
||||
// then that also defines an empty space at the edge.
|
||||
// Sub-rectangles may be defined partly or wholly out of the bounds of the
|
||||
// given rectangle. Such portions are ignored.
|
||||
using Child = std::pair< wxCoord, std::shared_ptr<TrackPanelNode> >;
|
||||
using Refinement = std::vector< Child >;
|
||||
using Subdivision = std::pair< Axis, Refinement >;
|
||||
|
||||
// Report a subdivision of one of the axes of the given rectangle
|
||||
virtual Subdivision Children( const wxRect &rect ) = 0;
|
||||
};
|
||||
|
||||
// Abstract base class defining TrackPanel's access to specialist classes that
|
||||
// implement drawing and user interactions
|
||||
class AUDACITY_DLL_API TrackPanelCell /* not final */
|
||||
class AUDACITY_DLL_API TrackPanelCell /* not final */ : public TrackPanelNode
|
||||
{
|
||||
public:
|
||||
virtual ~TrackPanelCell () = 0;
|
||||
|
@ -1,76 +0,0 @@
|
||||
/**********************************************************************
|
||||
|
||||
Audacity: A Digital Audio Editor
|
||||
|
||||
TrackPanelCellIterator.h
|
||||
|
||||
Paul Licameli
|
||||
|
||||
**********************************************************************/
|
||||
|
||||
#ifndef __AUDACITY_TRACK_PANEL_CELL_ITERATOR__
|
||||
#define __AUDACITY_TRACK_PANEL_CELL_ITERATOR__
|
||||
|
||||
#include "Track.h"
|
||||
#include <wx/gdicmn.h>
|
||||
#include <iterator>
|
||||
#include "MemoryX.h"
|
||||
|
||||
class Track;
|
||||
class TrackPanelCell;
|
||||
|
||||
class TrackPanel;
|
||||
|
||||
// A class that allows iteration over the rectangles of visible cells.
|
||||
class TrackPanelCellIterator
|
||||
: public std::iterator<
|
||||
std::forward_iterator_tag,
|
||||
const std::pair< std::shared_ptr< TrackPanelCell >, wxRect>
|
||||
>
|
||||
{
|
||||
public:
|
||||
enum class CellType {
|
||||
Track, Label, VRuler, Resizer, Background
|
||||
};
|
||||
|
||||
TrackPanelCellIterator(TrackPanel *trackPanel, bool begin);
|
||||
|
||||
// implement the STL iterator idiom
|
||||
|
||||
TrackPanelCellIterator &operator++ ();
|
||||
TrackPanelCellIterator operator++ (int);
|
||||
|
||||
friend inline bool operator==
|
||||
(const TrackPanelCellIterator &lhs, const TrackPanelCellIterator &rhs)
|
||||
{
|
||||
return lhs.mpCell == rhs.mpCell &&
|
||||
lhs.mDidBackground == rhs.mDidBackground;
|
||||
}
|
||||
|
||||
value_type operator * () const;
|
||||
|
||||
private:
|
||||
void UpdateRect();
|
||||
|
||||
TrackPanel *mPanel;
|
||||
TrackIter<Track> mIter;
|
||||
std::shared_ptr<Track> mpTrack;
|
||||
std::shared_ptr<TrackPanelCell> mpCell;
|
||||
CellType mType{ CellType::Track };
|
||||
bool mDidBackground{ false };
|
||||
wxRect mRect;
|
||||
};
|
||||
|
||||
inline TrackPanelCellIterator::CellType &operator++
|
||||
( TrackPanelCellIterator::CellType &type )
|
||||
{
|
||||
type = TrackPanelCellIterator::CellType( 1 + int( type ) );
|
||||
return type;
|
||||
}
|
||||
|
||||
inline bool operator !=
|
||||
(const TrackPanelCellIterator &lhs, const TrackPanelCellIterator &rhs)
|
||||
{
|
||||
return !(lhs == rhs);
|
||||
}
|
||||
#endif
|
@ -15,7 +15,6 @@ Paul Licameli split from TrackPanel.cpp
|
||||
#include "UIHandle.h"
|
||||
|
||||
class Track;
|
||||
class TrackPanelCellIterator;
|
||||
|
||||
class TrackPanelResizeHandle final : public UIHandle
|
||||
{
|
||||
|
@ -29,7 +29,6 @@ public:
|
||||
|
||||
std::shared_ptr<Track> FindTrack() override { return mpTrack.lock(); };
|
||||
private:
|
||||
friend class TrackPanelCellIterator;
|
||||
std::weak_ptr<Track> mpTrack;
|
||||
|
||||
std::weak_ptr<TrackPanelResizeHandle> mResizeHandle;
|
||||
|
@ -15,8 +15,6 @@ Paul Licameli split from TrackPanel.cpp
|
||||
#include "../../AColor.h"
|
||||
#include "../../AdornedRulerPanel.h"
|
||||
#include "../../Project.h"
|
||||
#include "../../TrackPanelCell.h"
|
||||
#include "../../TrackPanelCellIterator.h"
|
||||
#include "../../TrackPanelAx.h"
|
||||
#include "../../ViewInfo.h"
|
||||
|
||||
@ -100,21 +98,19 @@ void EditCursorOverlay::Draw(OverlayPanel &panel, wxDC &dc)
|
||||
AColor::CursorColor(&dc);
|
||||
|
||||
// Draw cursor in all selected tracks
|
||||
for ( const auto &data : tp->Cells() )
|
||||
{
|
||||
Track *const pTrack = dynamic_cast<Track*>(data.first.get());
|
||||
tp->VisitCells( [&]( const wxRect &rect, TrackPanelCell &cell ) {
|
||||
const auto pTrack = dynamic_cast<Track*>(&cell);
|
||||
if (!pTrack)
|
||||
continue;
|
||||
return;
|
||||
if (pTrack->GetSelected() ||
|
||||
mProject->GetTrackPanel()->GetAx().IsFocused(pTrack))
|
||||
{
|
||||
const wxRect &rect = data.second;
|
||||
// AColor::Line includes both endpoints so use GetBottom()
|
||||
AColor::Line(dc, mLastCursorX, rect.GetTop(), mLastCursorX, rect.GetBottom());
|
||||
// ^^^ The whole point of this routine.
|
||||
|
||||
}
|
||||
}
|
||||
} );
|
||||
}
|
||||
else if (auto ruler = dynamic_cast<AdornedRulerPanel*>(&panel)) {
|
||||
wxASSERT(!mIsMaster);
|
||||
|
@ -16,8 +16,6 @@ Paul Licameli split from TrackPanel.cpp
|
||||
#include "../../AudioIO.h"
|
||||
#include "../../Project.h"
|
||||
#include "../../TrackPanel.h"
|
||||
#include "../../TrackPanelCell.h"
|
||||
#include "../../TrackPanelCellIterator.h"
|
||||
#include "Scrubbing.h"
|
||||
|
||||
#include <wx/dc.h>
|
||||
@ -82,9 +80,8 @@ void PlayIndicatorOverlayBase::Draw(OverlayPanel &panel, wxDC &dc)
|
||||
wxASSERT(mIsMaster);
|
||||
|
||||
// Draw indicator in all visible tracks
|
||||
for ( const auto &data : tp->Cells() )
|
||||
{
|
||||
Track *const pTrack = dynamic_cast<Track*>(data.first.get());
|
||||
tp->VisitCells( [&]( const wxRect &rect, TrackPanelCell &cell ) {
|
||||
const auto pTrack = dynamic_cast<Track*>(&cell);
|
||||
if (pTrack) pTrack->TypeSwitch(
|
||||
[](LabelTrack *) {
|
||||
// Don't draw the indicator in label tracks
|
||||
@ -92,7 +89,6 @@ void PlayIndicatorOverlayBase::Draw(OverlayPanel &panel, wxDC &dc)
|
||||
[&](Track *) {
|
||||
// Draw the NEW indicator in its NEW location
|
||||
// AColor::Line includes both endpoints so use GetBottom()
|
||||
const wxRect &rect = data.second;
|
||||
AColor::Line(dc,
|
||||
mLastIndicatorX,
|
||||
rect.GetTop(),
|
||||
@ -100,7 +96,7 @@ void PlayIndicatorOverlayBase::Draw(OverlayPanel &panel, wxDC &dc)
|
||||
rect.GetBottom());
|
||||
}
|
||||
);
|
||||
}
|
||||
} );
|
||||
}
|
||||
else if(auto ruler = dynamic_cast<AdornedRulerPanel*>(&panel)) {
|
||||
wxASSERT(!mIsMaster);
|
||||
|
@ -545,7 +545,6 @@
|
||||
<ClInclude Include="..\..\..\src\toolbars\SpectralSelectionBar.h" />
|
||||
<ClInclude Include="..\..\..\src\toolbars\SpectralSelectionBarListener.h" />
|
||||
<ClInclude Include="..\..\..\src\TrackPanelCell.h" />
|
||||
<ClInclude Include="..\..\..\src\TrackPanelCellIterator.h" />
|
||||
<ClInclude Include="..\..\..\src\TrackPanelDrawingContext.h" />
|
||||
<ClInclude Include="..\..\..\src\TrackPanelListener.h" />
|
||||
<ClInclude Include="..\..\..\src\TrackPanelMouseEvent.h" />
|
||||
|
@ -1978,9 +1978,6 @@
|
||||
<ClInclude Include="..\..\..\src\tracks\ui\Scrubbing.h">
|
||||
<Filter>src\tracks\ui</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\..\src\TrackPanelCellIterator.h">
|
||||
<Filter>src</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\..\src\commands\CommandFunctors.h">
|
||||
<Filter>src\commands</Filter>
|
||||
</ClInclude>
|
||||
|
Loading…
x
Reference in New Issue
Block a user