/********************************************************************** Tenacity CellularPanel.h Paul Licameli **********************************************************************/ #ifndef __AUDACITY_CELLULAR_PANEL__ #define __AUDACITY_CELLULAR_PANEL__ #include "widgets/OverlayPanel.h" // to inherit class ViewInfo; class AudacityProject; class TrackPanelCell; struct TrackPanelDrawingContext; class TrackPanelGroup; class TrackPanelNode; struct TrackPanelMouseEvent; struct TrackPanelMouseState; class TranslatableString; class UIHandle; using UIHandlePtr = std::shared_ptr; // This class manages a panel divided into a number of sub-rectangles called // cells, that each implement hit tests returning click-drag-release handler // objects, and other services. // It has no dependency on the Track class. class TENACITY_DLL_API CellularPanel : public OverlayPanel { public: CellularPanel(wxWindow * parent, wxWindowID id, const wxPoint & pos, const wxSize & size, ViewInfo *viewInfo, // default as for wxPanel: long style = wxTAB_TRAVERSAL | wxNO_BORDER); ~CellularPanel() override; // Overridables: virtual AudacityProject *GetProject() const = 0; // Get the root object defining a recursive subdivision of the panel's // area into cells virtual std::shared_ptr Root() = 0; virtual TrackPanelCell *GetFocusedCell() = 0; virtual void SetFocusedCell() = 0; virtual void ProcessUIHandleResult (TrackPanelCell *pClickedCell, TrackPanelCell *pLatestCell, unsigned refreshResult) = 0; virtual void UpdateStatusMessage( const TranslatableString & ) = 0; public: // 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 ); // 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); // Search the tree of subdivisions of the panel area for a node (group or // cell) satisfying the predicate. If more than one sub-area is associated // with some node satisfying the predicate, it is not specified which // rectangle is returned. wxRect FindRect(const std::function< bool( TrackPanelNode& ) > &pred); UIHandlePtr Target(); std::shared_ptr LastCell() const; bool IsMouseCaptured(); wxCoord MostRecentXCoord() const; void HandleCursorForPresentMouseState(bool doHit = true); // Visit the Draw functions of all cells that intersect the panel area, // and of handles associated with such cells, // and of all groups of cells, // repeatedly with a pass count from 0 to nPasses - 1 void Draw( TrackPanelDrawingContext &context, unsigned nPasses ); protected: bool HasEscape(); bool CancelDragging( bool escaping ); void DoContextMenu( TrackPanelCell *pCell = nullptr ); void ClearTargets(); private: void Visit( const wxRect &rect, const std::shared_ptr &node, Visitor &visitor ); bool HasRotation(); bool ChangeTarget(bool forward, bool cycle); void OnMouseEvent(wxMouseEvent & event); void OnCaptureLost(wxMouseCaptureLostEvent & event); void OnCaptureKey(wxCommandEvent & event); void OnKeyDown(wxKeyEvent & event); void OnChar(wxKeyEvent & event); void OnKeyUp(wxKeyEvent & event); void OnSetFocus(wxFocusEvent & event); void OnKillFocus(wxFocusEvent & event); void OnContextMenu(wxContextMenuEvent & event); void HandleInterruptedDrag(); void Uncapture( bool escaping, wxMouseState *pState = nullptr ); bool HandleEscapeKey(bool down); void UpdateMouseState(const wxMouseState &state); void HandleModifierKey(); void HandleClick( const TrackPanelMouseEvent &tpmEvent ); void HandleWheelRotation( TrackPanelMouseEvent &tpmEvent ); void HandleMotion( wxMouseState &state, bool doHit = true ); void HandleMotion ( const TrackPanelMouseState &tpmState, bool doHit = true ); void Leave(); protected: ViewInfo *mViewInfo; // To do: make a drawing method and make this private wxMouseState mLastMouseState; private: struct State; std::unique_ptr mState; struct Filter; DECLARE_EVENT_TABLE() }; #endif