33#include <wx/eventfilter.h>
48 wxEvtHandler::AddFilter(
this );
53 wxEvtHandler::RemoveFilter(
this );
63 const auto type =
event.GetEventType();
64 if (type == wxEVT_KEY_DOWN &&
65 static_cast< wxKeyEvent&
>( event ).GetKeyCode() == WXK_ESCAPE ) {
66 bool eatEvent =
false;
73 pPanel->HandleEscapeKey(
true );
77 return Event_Processed;
79 else if ((type == wxEVT_LEFT_DOWN ||
80 type == wxEVT_RIGHT_DOWN ||
81 type == wxEVT_MIDDLE_DOWN)) {
131 wxWindow * parent, wxWindowID
id,
132 const wxPoint & pos, const wxSize &
size,
136, mViewInfo( viewInfo )
137,
mState{ std::make_unique<State>() }
150 if (state.mUIHandle &&
151 state.mUIHandle->StopsOnKeystroke() ) {
155 const int idBogusUp = 2;
156 wxMouseEvent evt { wxEVT_LEFT_UP };
157 evt.SetId( idBogusUp );
158 evt.SetPosition(this->ScreenToClient(::wxGetMousePosition()));
159 this->ProcessEvent(evt);
165 auto state = ::wxGetMouseState();
168 state.SetPosition(this->ScreenToClient(state.GetPosition()));
176 if ( escaping || !AcceptsFocus() )
183 if (state.mUIHandle) {
185 auto handle = state.mUIHandle;
188 auto pClickedCell = state.mpClickedCell.lock();
191 pClickedCell.get(), {},
192 refreshResult | state.mMouseOverUpdateFlags );
193 state.mpClickedCell.reset();
194 state.mUIHandle.reset(), handle.reset(),
ClearTargets();
209 if (target && target->HasEscape(pProject) && target->Escape(pProject)) {
216 if (state.mUIHandle) {
235 if (!state.ButtonIsDown(wxMOUSE_BTN_ANY)) {
237 if (state.RawControlDown())
262 auto state = ::wxGetMouseState();
264 state.SetPosition(this->ScreenToClient(state.GetPosition()));
280 const auto foundCell =
FindCell( inState.m_x, inState.m_y );
281 auto &rect = foundCell.rect;
282 auto &pCell = foundCell.pCell;
291 auto handle = state.mUIHandle;
293 auto newCell = tpmState.
pCell;
294 auto oldCell = state.mLastCell.lock();
295 auto oldHandle =
Target();
299 unsigned refreshCode = 0;
305 refreshCode = state.mMouseOverUpdateFlags;
306 state.mMouseOverUpdateFlags = 0;
308 else if ( !state.mUIHandle ) {
311 unsigned updateFlags = state.mMouseOverUpdateFlags;
314 if ( newCell == oldCell )
322 oldCell.get(), oldCell.get(), updateFlags);
326 auto oldPosition = state.mTarget;
330 state.mTargets.clear();
332 state.mTargets = newCell->HitTest(tpmState,
GetProject());
337 auto begin = state.mTargets.begin(),
end = state.mTargets.end(),
338 iter = std::find(
begin,
end, oldHandle);
340 size_t newPosition = iter -
begin;
341 if (newPosition <= oldPosition)
342 state.mTarget = newPosition;
349 state.mLastCell = newCell;
358 if (!oldCell && oldHandle != handle)
360 refreshCode = updateFlags;
363 if (handle && handle != oldHandle)
366 if (oldHandle == handle)
373 auto preview = handle->Preview( tpmState,
GetProject() );
374 status = preview.message;
375 tooltip = preview.tooltip;
376 pCursor = preview.cursor;
377 auto code = handle->GetChangeHighlight();
380 state.mMouseOverUpdateFlags |= code;
383 (!pCursor || status.
empty() || tooltip.
empty())) {
386 const auto preview = newCell->DefaultPreview( tpmState,
GetProject() );
388 pCursor = preview.cursor;
390 status = preview.message;
392 tooltip = preview.tooltip;
396 static wxCursor defaultCursor{ wxCURSOR_DEFAULT };
397 pCursor = &defaultCursor;
402 if (handle || (newCell && !wxWindow::GetCapture())) {
409 if (handle != oldHandle)
415 SetCursor( *pCursor );
417 else if ( oldCell || oldHandle )
428 auto state = ::wxGetMouseState();
430 std::shared_ptr<TrackPanelCell> pCell;
439 if ( state.mTargets.size() > 1 )
442 return target && target->HasRotation();
451 if (state.mTarget + 1 == state.mTargets.size() &&
456 return state.mTargets.size() > 0;
462 auto size = state.mTargets.size();
465 if (target && target->HasRotation()) {
466 if(target->Rotate(forward))
476 ((forward && state.mTarget + 1 ==
size) ||
477 (!forward && state.mTarget == 0)))
484 state.mTarget +=
size - 1;
485 state.mTarget %=
size;
498 return state.mUIHandle != NULL;
509 auto pCell = tpmEvent.
pCell;
513 auto &
event = tpmEvent.
event;
515#if defined(__WXMAC__) && defined(EVT_MAGNIFY)
519 if (event.Magnify()) {
520 event.SetControlDown(
true);
521 steps = 2 *
event.GetMagnification();
526 steps =
event.m_wheelRotation /
527 (
event.m_wheelDelta > 0 ? (double)event.m_wheelDelta : 120.0);
530 if(event.GetWheelAxis() == wxMOUSE_WHEEL_HORIZONTAL) {
532 event.SetShiftDown(
true);
538 tpmEvent.
steps = steps;
540 if(!event.HasAnyModifiers()) {
544 event.ResumePropagation(wxEVENT_PROPAGATE_MAX);
548 pCell->HandleWheelRotation( tpmEvent,
GetProject() );
550 pCell.get(), pCell.get(), result);
556 state.mEnableTab =
false;
557 wxKeyEvent *kevent =
static_cast<wxKeyEvent *
>(
event.GetEventObject());
558 const auto code = kevent->GetKeyCode();
559 if ( WXK_ESCAPE != code )
565 const unsigned refreshResult =
568 event.Skip(kevent->GetSkipped());
573 if ( !(t && !kevent->GetSkipped()) &&
588 switch (event.GetKeyCode())
603 case WXK_RAW_CONTROL:
623 const unsigned refreshResult =
633 switch (event.GetKeyCode())
646 const unsigned refreshResult =
656 bool didSomething =
false;
657 switch (event.GetKeyCode())
667 case WXK_RAW_CONTROL:
678 const unsigned refreshResult =
691 state.mUIHandle.reset();
695 wxMouseEvent e(wxEVT_LEFT_UP);
698 e.m_x = state.mMouseMostRecentX;
699 e.m_y = state.mMouseMostRecentY;
710 const auto foundCell =
FindCell( event.m_x, event.m_y );
711 auto &rect = foundCell.rect;
712 auto &pCell = foundCell.pCell;
714 const auto size = GetSize();
717#if defined(__WXMAC__) && defined(EVT_MAGNIFY)
721 if (event.Magnify()) {
731 if (event.GetPosition() == wxDefaultPosition && (event.RightDown() || event.RightUp())) {
736 if (event.m_wheelRotation != 0)
739 if (event.LeftDown() || event.LeftIsDown() || event.Moving()) {
743 event.ResumePropagation(wxEVENT_PROPAGATE_MAX);
747 state.mMouseMostRecentX =
event.m_x;
748 state.mMouseMostRecentY =
event.m_y;
750 if (event.LeftDown()) {
754 GetParent()->GetEventHandler()->ProcessEvent(e);
757 if (event.Entering())
761 else if (event.Leaving())
771 ::wxGetMouseState().ButtonIsDown(wxMOUSE_BTN_ANY);
776#if defined(__WXMAC__)
781 wxSTANDARD_CURSOR->MacInstall();
786 if (state.mUIHandle) {
787 auto pClickedCell = state.mpClickedCell.lock();
788 if (event.Dragging()) {
791 auto handle = state.mUIHandle;
795 (pClickedCell.get(), pCell.get(), refreshResult);
796 state.mMouseOverUpdateFlags |= refreshResult;
799 state.mUIHandle.reset(), handle.reset(),
ClearTargets();
800 state.mpClickedCell.reset();
809 else if (event.ButtonUp()) {
812 auto handle = state.mUIHandle;
813 unsigned moreFlags = state.mMouseOverUpdateFlags;
815 handle->Release( tpmEvent,
GetProject(),
this );
817 (pClickedCell.get(), pCell.get(),
818 refreshResult | moreFlags);
819 state.mUIHandle.reset(), handle.reset(),
ClearTargets();
820 state.mpClickedCell.reset();
824 else if ( event.GetEventType() == wxEVT_MOTION )
830 else if ( event.ButtonDown() || event.ButtonDClick() )
838 if (event.ButtonUp())
844 if ( CancelDragging(
true ) )
858 const std::shared_ptr<TrackPanelCell> &pCell )
884 wxWindow *pParent)
override
886 if (
auto pCell = mwCell.lock()) {
887 auto point =
event.event.GetPosition();
888 return pCell->DoContextMenu(event.
rect, pParent, &point, pProject);
902DefaultRightButtonHandler::~DefaultRightButtonHandler()
910 auto pCell = tpmEvent.
pCell;
923 state.mUIHandle =
Target();
924 if (tpmEvent.
event.RightDown() &&
925 !(state.mUIHandle && state.mUIHandle->HandlesRightClick())) {
926 if (
auto pCell = state.mLastCell.lock())
927 state.mUIHandle = std::make_shared<DefaultRightButtonHandler>(pCell);
930 if (state.mUIHandle) {
934 auto handle = state.mUIHandle;
938 state.mUIHandle.reset(), handle.reset(),
ClearTargets();
947 if( !HasFocus() && AcceptsFocus() )
948 SetFocusIgnoringChildren();
950 state.mpClickedCell = pCell;
962 pCell.get(), pCell.get(), refreshResult);
963 state.mMouseOverUpdateFlags |= refreshResult;
981 delegate->DoContextMenu(rect,
this,
nullptr,
GetProject());
996 auto refreshResult = pCell->LoseFocus(
GetProject());
998 auto pClickedCell = state.mpClickedCell.lock();
1026 Visit( GetClientRect(),
Root(), visitor );
1045 : function{ function_ }, pre{ pre_ }, post{ ! pre_ } {}
1048 {
return function( rect, cell ); }
1050 {
if (pre)
return function( rect, group ); }
1052 {
if (post)
return function( rect, group ); }
1055 const bool pre{
false }, post{
false };
1063 Adaptor adaptor{ visitor };
1069 Adaptor adaptor{ visitor,
true };
1075 Adaptor adaptor{ visitor,
false };
1081 const wxRect &rect,
bool divideX,
1083 const TrackPanelGroup::Refinement::const_iterator iter)
1085 const auto next = iter + 1;
1086 const auto end = children.end();
1089 nextCoord = std::max( iter->first,
1090 divideX ? rect.GetRight() : rect.GetBottom() );
1092 nextCoord = next->first - 1;
1094 auto lesser = iter->first;
1095 auto greater = nextCoord;
1099 result.SetLeft(lesser), result.SetRight(greater);
1101 result.SetTop(lesser), result.SetBottom(greater);
1109 const wxRect &rect,
const std::shared_ptr<TrackPanelNode> &node,
1118 const auto results = pGroup->Children( rect );
1120 const auto &children = results.second;
1121 const auto begin = children.begin(),
end = children.end();
1122 for (
auto iter =
begin; iter !=
end; ++iter)
1124 Subdivide(rect, divideX, children, iter), iter->second, visitor );
1134 auto rect = this->GetClientRect();
1137 if (
auto pCell = std::dynamic_pointer_cast< TrackPanelCell >( node ) )
1139 return { pCell, rect };
1140 else if (
auto pGroup =
dynamic_cast< TrackPanelGroup*
>( node.get() ) ) {
1142 const auto results = pGroup->Children( rect );
1144 const auto &children = results.second;
1147 const auto begin = children.begin(),
end = children.end();
1148 auto iter = std::upper_bound(
begin,
end,
1149 (divideX ? mouseX : mouseY),
1151 return coord < child.first;
1159 rect =
Subdivide(rect, divideX, children, iter);
1160 node = iter->second;
1177 if ( &visited == &cell )
1178 result = rect,
throw Stop{};
1180 catch (
const Stop& ) {}
1192 if ( pred( visited ) )
1193 result = rect,
throw Stop{};
1195 catch (
const Stop& ) {}
1203 if (state.mTargets.size())
1204 return state.mTargets[state.mTarget];
1212 return state.mMouseMostRecentX;
1220 state.mLastCell.reset();
1221 state.mTargets.clear();
1223 state.mMouseOverUpdateFlags = 0;
1229 return state.mLastCell.lock();
1234 const auto panelRect = GetClientRect();
1236 for (
unsigned iPass = 0; iPass < nPasses; ++iPass ) {
1242 context, rect, panelRect, iPass );
1243 if ( newRect.Intersects( panelRect ) )
1244 node.
Draw( context, newRect, iPass );
1247 if ( &node == lastCell.get() ) {
1248 auto target = Target();
1250 const auto targetRect =
1251 target->DrawingArea( context, rect, panelRect, iPass );
1252 if ( targetRect.Intersects( panelRect ) )
1253 target->Draw( context, targetRect, iPass );
std::shared_ptr< UIHandle > UIHandlePtr
EVT_COMMAND(wxID_ANY, EVT_FREQUENCYTEXTCTRL_UPDATED, LabelDialog::OnFreqUpdate) LabelDialog
const int kCaptureLostEventId
The top-level handle to an Audacity project. It serves as a source of events that other objects can b...
Formerly part of TrackPanel, this abstract base class has no special knowledge of Track objects and i...
void Draw(TrackPanelDrawingContext &context, unsigned nPasses)
bool IsMouseCaptured()
Determines if a modal tool is active.
void DoContextMenu(TrackPanelCell *pCell=nullptr)
void UpdateMouseState(const wxMouseState &state)
virtual std::shared_ptr< TrackPanelNode > Root()=0
virtual AudacityProject * GetProject() const =0
std::unique_ptr< State > mState
void VisitCells(const SimpleCellVisitor &visitor)
void OnKeyDown(wxKeyEvent &event)
void VisitPreorder(const SimpleNodeVisitor &visitor)
FoundCell FindCell(int mouseX, int mouseY)
void HandleWheelRotation(TrackPanelMouseEvent &tpmEvent)
Handle mouse wheel rotation (for zoom in/out, vertical and horizontal scrolling)
wxRect FindRect(const TrackPanelCell &cell)
~CellularPanel() override
void OnCaptureKey(wxCommandEvent &event)
bool HandleEscapeKey(bool down)
bool CancelDragging(bool escaping)
void OnMouseEvent(wxMouseEvent &event)
void OnKeyUp(wxKeyEvent &event)
void OnChar(wxKeyEvent &event)
std::shared_ptr< TrackPanelCell > LastCell() const
void VisitPostorder(const SimpleNodeVisitor &visitor)
void HandleMotion(wxMouseState &state, bool doHit=true)
virtual void UpdateStatusMessage(const TranslatableString &)=0
void HandleClick(const TrackPanelMouseEvent &tpmEvent)
void OnSetFocus(wxFocusEvent &event)
void OnCaptureLost(wxMouseCaptureLostEvent &event)
Should handle the case when the mouse capture is lost. (MSW only)
std::function< void(const wxRect &rect, TrackPanelCell &cell) > SimpleCellVisitor
virtual void SetFocusedCell()=0
void HandleInterruptedDrag()
void OnKillFocus(wxFocusEvent &event)
wxMouseState mLastMouseState
void OnContextMenu(wxContextMenuEvent &event)
std::function< void(const wxRect &rect, TrackPanelNode &node) > SimpleNodeVisitor
bool ChangeTarget(bool forward, bool cycle)
void Uncapture(bool escaping, wxMouseState *pState=nullptr)
virtual TrackPanelCell * GetFocusedCell()=0
void Visit(Visitor &visitor)
wxCoord MostRecentXCoord() const
virtual void ProcessUIHandleResult(TrackPanelCell *pClickedCell, TrackPanelCell *pLatestCell, unsigned refreshResult)=0
void HandleCursorForPresentMouseState(bool doHit=true)
virtual std::shared_ptr< TrackPanelCell > ContextMenuDelegate()
virtual void Draw(TrackPanelDrawingContext &context, const wxRect &rect, unsigned iPass)
virtual wxRect DrawingArea(TrackPanelDrawingContext &context, const wxRect &rect, const wxRect &panelRect, unsigned iPass)
std::vector< Child > Refinement
std::pair< wxCoord, std::shared_ptr< TrackPanelNode > > Child
The TrackPanel is built up of nodes, subtrees of the CellularPanel's area Common base class for Track...
Holds a msgid for the translation catalog; may also bind format arguments.
wxString Translation() const
Short-lived drawing and event-handling object associated with a TrackPanelCell.
void SetToolTip(const TranslatableString &toolTip)
bool IsHandler(const wxWindow *handler)
void Release(wxWindow *handler)
auto end(const Ptr< Type, BaseDeleter > &p)
Enables range-for.
auto begin(const Ptr< Type, BaseDeleter > &p)
Enables range-for.
wxRect Subdivide(const wxRect &rect, bool divideX, const TrackPanelGroup::Refinement &children, const TrackPanelGroup::Refinement::const_iterator iter)
int FilterEvent(wxEvent &event) override
static wxWeakRef< CellularPanel > spClickedPanel
static wxWeakRef< CellularPanel > spEnteredPanel
unsigned mMouseOverUpdateFlags
std::weak_ptr< TrackPanelCell > mLastCell
std::vector< UIHandlePtr > mTargets
std::weak_ptr< TrackPanelCell > mpClickedCell
virtual void EndGroup(const wxRect &rect, TrackPanelGroup &group)
virtual void BeginGroup(const wxRect &rect, TrackPanelGroup &group)
virtual void VisitCell(const wxRect &rect, TrackPanelCell &cell)
std::shared_ptr< TrackPanelCell > pCell
std::shared_ptr< TrackPanelCell > pCell
void EndGroup(const wxRect &rect, TrackPanelGroup &group) override
void VisitCell(const wxRect &rect, TrackPanelCell &cell) override
CellularPanel::SimpleCellVisitor SimpleCellVisitor
Adaptor(const SimpleCellVisitor &function_)
CellularPanel::SimpleNodeVisitor SimpleNodeVisitor
SimpleNodeVisitor function
void BeginGroup(const wxRect &rect, TrackPanelGroup &group) override
Adaptor(const SimpleNodeVisitor &function_, bool pre_)