mirror of
https://github.com/cookiengineer/audacity
synced 2025-07-31 07:59:27 +02:00
Define visitation procedure skeleton for subdivision of CellularPanel
This commit is contained in:
parent
4fe97acbc9
commit
588c050bbb
@ -860,6 +860,122 @@ void CellularPanel::OnKillFocus(wxFocusEvent & WXUNUSED(event))
|
|||||||
Refresh( false);
|
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);
|
||||||
|
|
||||||
|
// Some defense against bad overrides of TrackPanelGroup::Children
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
UIHandlePtr CellularPanel::Target()
|
UIHandlePtr CellularPanel::Target()
|
||||||
{
|
{
|
||||||
auto &state = *mState;
|
auto &state = *mState;
|
||||||
|
@ -18,6 +18,7 @@ class ViewInfo;
|
|||||||
class AudacityProject;
|
class AudacityProject;
|
||||||
|
|
||||||
class TrackPanelCell;
|
class TrackPanelCell;
|
||||||
|
class TrackPanelGroup;
|
||||||
class TrackPanelNode;
|
class TrackPanelNode;
|
||||||
struct TrackPanelMouseEvent;
|
struct TrackPanelMouseEvent;
|
||||||
struct TrackPanelMouseState;
|
struct TrackPanelMouseState;
|
||||||
@ -55,6 +56,29 @@ public:
|
|||||||
|
|
||||||
virtual FoundCell FindCell(int mouseX, int mouseY) = 0;
|
virtual FoundCell FindCell(int mouseX, int mouseY) = 0;
|
||||||
virtual wxRect FindRect(const TrackPanelCell &cell) = 0;
|
virtual wxRect FindRect(const TrackPanelCell &cell) = 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 );
|
||||||
|
};
|
||||||
|
|
||||||
|
// 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 TrackPanelCell *GetFocusedCell() = 0;
|
||||||
virtual void SetFocusedCell() = 0;
|
virtual void SetFocusedCell() = 0;
|
||||||
|
|
||||||
@ -86,6 +110,10 @@ protected:
|
|||||||
void ClearTargets();
|
void ClearTargets();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
void Visit(
|
||||||
|
const wxRect &rect, const std::shared_ptr<TrackPanelNode> &node,
|
||||||
|
Visitor &visitor );
|
||||||
|
|
||||||
bool HasRotation();
|
bool HasRotation();
|
||||||
bool ChangeTarget(bool forward, bool cycle);
|
bool ChangeTarget(bool forward, bool cycle);
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user