1 /**********************************************************************
2 
3 Audacity: A Digital Audio Editor
4 
5 CommonTrackPanelCell.cpp
6 
7 Paul Licameli split from TrackPanel.cpp
8 
9 **********************************************************************/
10 
11 #include "CommonTrackPanelCell.h"
12 
13 #include <wx/cursor.h>
14 #include <wx/event.h>
15 #include <wx/menu.h>
16 
17 #include "../../widgets/BasicMenu.h"
18 #include "BasicUI.h"
19 #include "../../commands/CommandContext.h"
20 #include "../../commands/CommandManager.h"
21 #include "../../HitTestResult.h"
22 #include "../../RefreshCode.h"
23 #include "../../TrackPanelMouseEvent.h"
24 #include "ViewInfo.h"
25 #include "../../widgets/wxWidgetsWindowPlacement.h"
26 
27 namespace {
GetHook()28    CommonTrackPanelCell::Hook &GetHook()
29    {
30       static CommonTrackPanelCell::Hook theHook;
31       return theHook;
32    }
33 }
34 
InstallMouseWheelHook(const Hook & hook)35 auto CommonTrackPanelCell::InstallMouseWheelHook( const Hook &hook )
36    -> Hook
37 {
38    auto &theHook = GetHook();
39    auto result = theHook;
40    theHook = hook;
41    return result;
42 }
43 
~CommonTrackPanelCell()44 CommonTrackPanelCell::~CommonTrackPanelCell()
45 {
46 }
47 
DefaultPreview(const TrackPanelMouseState &,const AudacityProject *)48 HitTestPreview CommonTrackPanelCell::DefaultPreview
49 (const TrackPanelMouseState &, const AudacityProject *)
50 {
51    static wxCursor defaultCursor{ wxCURSOR_ARROW };
52    return { {}, &defaultCursor, {} };
53 }
54 
GetMenuItems(const wxRect &,const wxPoint *,AudacityProject *)55 auto CommonTrackPanelCell::GetMenuItems(
56    const wxRect&, const wxPoint *, AudacityProject * )
57       -> std::vector<MenuItem>
58 {
59    return {};
60 }
61 
DoContextMenu(const wxRect & rect,wxWindow * pParent,const wxPoint * pPoint,AudacityProject * pProject)62 unsigned CommonTrackPanelCell::DoContextMenu( const wxRect &rect,
63    wxWindow *pParent, const wxPoint *pPoint, AudacityProject *pProject)
64 {
65    const auto items = GetMenuItems( rect, pPoint, pProject );
66    if (items.empty())
67       return RefreshCode::RefreshNone;
68 
69    // Set up command context with extras
70    CommandContext context{ *pProject };
71    SelectedRegion region;
72    if (pPoint) {
73       auto time = ViewInfo::Get(*pProject).PositionToTime(pPoint->x, rect.x);
74       region = { time, time };
75       context.temporarySelection.pSelectedRegion = &region;
76    }
77    context.temporarySelection.pTrack = FindTrack().get();
78 
79    auto &commandManager = CommandManager::Get(*pProject);
80    auto flags = MenuManager::Get( *pProject ).GetUpdateFlags();
81 
82    // Common dispatcher for the menu items
83    auto dispatcher = [&]( wxCommandEvent &evt ){
84       auto idx = evt.GetId() - 1;
85       if (idx >= 0 && idx < items.size()) {
86          if (auto &action = items[idx].action)
87             action( context );
88          else
89             commandManager.HandleTextualCommand(
90                items[idx].symbol.Internal(), context, flags, false);
91       }
92    };
93 
94    wxMenu menu;
95    int ii = 1;
96    for (const auto &item: items) {
97       if ( const auto &commandID = item.symbol.Internal();
98            commandID.empty() )
99          menu.AppendSeparator();
100       else {
101          // Generate a menu item with the same shortcut key as in the toolbar
102          // menu, and as determined by keyboard preferences
103          auto label =
104             commandManager.FormatLabelForMenu( commandID, &item.symbol.Msgid() );
105          menu.Append( ii, label );
106          menu.Bind( wxEVT_COMMAND_MENU_SELECTED, dispatcher );
107          bool enabled = item.enabled &&
108             (item.action || commandManager.GetEnabled( commandID ));
109          menu.Enable( ii, enabled );
110       }
111       ++ii;
112    }
113 
114    BasicUI::Point point;
115    if (pPoint)
116       point = { pPoint->x, pPoint->y };
117    BasicMenu::Handle{ &menu }.Popup(
118       wxWidgetsWindowPlacement{ pParent },
119       point
120    );
121 
122    return RefreshCode::RefreshNone;
123 }
124 
HandleWheelRotation(const TrackPanelMouseEvent & evt,AudacityProject * pProject)125 unsigned CommonTrackPanelCell::HandleWheelRotation
126 (const TrackPanelMouseEvent &evt, AudacityProject *pProject)
127 {
128    auto hook = GetHook();
129    return hook ? hook( evt, pProject ) : RefreshCode::Cancelled;
130 }
131 
CommonTrackCell(const std::shared_ptr<Track> & parent)132 CommonTrackCell::CommonTrackCell( const std::shared_ptr< Track > &parent )
133    : mwTrack { parent }
134 {}
135 
136 CommonTrackCell::~CommonTrackCell() = default;
137 
CopyTo(Track &) const138 void CommonTrackCell::CopyTo( Track& ) const
139 {
140 }
141 
Reparent(const std::shared_ptr<Track> & parent)142 void CommonTrackCell::Reparent( const std::shared_ptr<Track> &parent )
143 {
144    mwTrack = parent;
145 }
146 
DoFindTrack()147 std::shared_ptr<Track> CommonTrackCell::DoFindTrack()
148 {
149    return mwTrack.lock();
150 }
151 
WriteXMLAttributes(XMLWriter &) const152 void CommonTrackCell::WriteXMLAttributes( XMLWriter & ) const
153 {
154 }
155 
HandleXMLAttribute(const std::string_view & attr,const XMLAttributeValueView & valueView)156 bool CommonTrackCell::HandleXMLAttribute(
157    const std::string_view& attr, const XMLAttributeValueView& valueView)
158 {
159    return false;
160 }
161