1 /********************************************************************** 2 3 Audacity: A Digital Audio Editor 4 5 Scrubbing.h 6 7 Paul Licameli split from TrackPanel.cpp 8 9 **********************************************************************/ 10 11 #ifndef __AUDACITY_SCRUBBING__ 12 #define __AUDACITY_SCRUBBING__ 13 14 15 16 #include <vector> 17 #include <wx/longlong.h> 18 19 #include "../../ScrubState.h" // for ScrubbingOptions 20 #include "ClientData.h" // to inherit 21 #include "Prefs.h" // to inherit 22 #include "../../widgets/Overlay.h" // to inherit 23 #include "../../commands/CommandContext.h" 24 #include "../../commands/CommandManager.h" // for MenuTable 25 #include "Identifier.h" 26 27 class AudacityProject; 28 class TranslatableString; 29 30 // Conditionally compile either a separate thead, or else use a timer in the main 31 // thread, to poll the mouse and update scrubbing speed and direction. The advantage of 32 // a thread may be immunity to choppy scrubbing in case redrawing takes too much time. 33 #ifdef __WXGTK__ 34 // Unfortunately some things the thread needs to do are not thread safe 35 #else 36 #define USE_SCRUB_THREAD 37 #endif 38 39 // Scrub state object 40 class AUDACITY_DLL_API Scrubber final 41 : public wxEvtHandler 42 , public ClientData::Base 43 , private PrefsListener 44 , public std::enable_shared_from_this< Scrubber > 45 { 46 public: 47 static Scrubber &Get( AudacityProject &project ); 48 static const Scrubber &Get( const AudacityProject &project ); 49 50 explicit 51 Scrubber(AudacityProject *project); 52 Scrubber( const Scrubber & ) PROHIBITED; 53 Scrubber &operator=( const Scrubber & ) PROHIBITED; 54 ~Scrubber(); 55 56 static bool ShouldScrubPinned(); 57 58 // Assume xx is relative to the left edge of TrackPanel! 59 void MarkScrubStart(wxCoord xx, bool smoothScrolling, bool seek); 60 61 // Returns true iff the event should be considered consumed by this: 62 // Assume xx is relative to the left edge of TrackPanel! 63 bool MaybeStartScrubbing(wxCoord xx); 64 bool StartKeyboardScrubbing(double time0, bool backwards); 65 double GetKeyboardScrubbingSpeed(); 66 67 void ContinueScrubbingUI(); 68 void ContinueScrubbingPoll(); 69 70 // This is meant to be called only from ProjectAudioManager 71 void StopScrubbing(); 72 GetScrubStartPosition()73 wxCoord GetScrubStartPosition() const 74 { return mScrubStartPosition; } 75 WasSpeedPlaying()76 bool WasSpeedPlaying() const 77 { return mSpeedPlaying;} IsSpeedPlaying()78 bool IsSpeedPlaying() const 79 { return IsScrubbing() && mSpeedPlaying; } WasKeyboardScrubbing()80 bool WasKeyboardScrubbing() const 81 { return mKeyboardScrubbing; } IsKeyboardScrubbing()82 bool IsKeyboardScrubbing() const 83 { return IsScrubbing() && mKeyboardScrubbing; } SetBackwards(bool backwards)84 void SetBackwards(bool backwards) 85 { mBackwards = backwards;} IsBackwards()86 bool IsBackwards() const 87 { return mBackwards;} 88 // True iff the user has clicked to start scrub and not yet stopped, 89 // but IsScrubbing() may yet be false HasMark()90 bool HasMark() const 91 { return GetScrubStartPosition() >= 0; } 92 bool IsScrubbing() const; 93 IsScrollScrubbing()94 bool IsScrollScrubbing() const // If true, implies HasMark() 95 { return mSmoothScrollingScrub; } SetScrollScrubbing(bool value)96 void SetScrollScrubbing(bool value) 97 { mSmoothScrollingScrub = value; } 98 99 bool ChoseSeeking() const; SetMayDragToSeek(bool value)100 void SetMayDragToSeek( bool value ) { mMayDragToSeek = value; } MayDragToSeek()101 bool MayDragToSeek() const { return mMayDragToSeek; } 102 bool TemporarilySeeks() const; 103 bool Seeks() const; 104 bool Scrubs() const; 105 bool ShowsBar() const; 106 Cancel()107 void Cancel() 108 { mCancelled = true; } 109 110 bool ShouldDrawScrubSpeed(); 111 double FindScrubSpeed(bool seeking, double time) const; GetMaxScrubSpeed()112 double GetMaxScrubSpeed() const { return mOptions.maxSpeed; } 113 114 void HandleScrollWheel(int steps); 115 116 // This returns the same as the enabled state of the menu items: 117 bool CanScrub() const; 118 119 // For popup 120 void PopulatePopupMenu(wxMenu &menu); 121 122 void OnScrubOrSeek(bool seek); 123 void OnScrub(const CommandContext&); 124 void OnSeek(const CommandContext&); 125 void OnToggleScrubRuler(const CommandContext&); 126 127 void OnKeyboardScrubBackwards(const CommandContext&); 128 void OnKeyboardScrubForwards(const CommandContext&); 129 void DoKeyboardScrub(bool backwards, bool keyUp); 130 131 // Convenience wrapper for the above 132 template<void (Scrubber::*pfn)(const CommandContext&)> Thunk(wxCommandEvent &)133 void Thunk(wxCommandEvent &) 134 { (this->*pfn)(*mProject); } 135 136 // A string to put in the leftmost part of the status bar 137 // when scrub or seek is in progress, or else empty. 138 const TranslatableString &GetUntranslatedStateString() const; 139 wxString StatusMessageForWave() const; 140 141 void Pause(bool paused); 142 bool IsPaused() const; 143 void CheckMenuItems(); 144 145 bool IsTransportingPinned() const; 146 SetSeekPress(bool value)147 void SetSeekPress( bool value ) { mScrubSeekPress = value; } 148 149 private: 150 void UpdatePrefs() override; 151 152 void StartPolling(); 153 void StopPolling(); 154 void DoScrub(bool seek); 155 void OnActivateOrDeactivateApp(wxActivateEvent & event); 156 157 private: 158 int mScrubToken; 159 int mScrubSpeedDisplayCountdown; 160 wxCoord mScrubStartPosition; 161 wxCoord mLastScrubPosition {}; 162 bool mScrubSeekPress {}; 163 bool mSmoothScrollingScrub; 164 165 bool mPaused{}; 166 bool mSeeking {}; 167 bool mSpeedPlaying{true}; 168 bool mKeyboardScrubbing{}; 169 bool mBackwards{}; 170 bool mDragging {}; 171 172 bool mCancelled {}; 173 174 #ifdef EXPERIMENTAL_SCRUBBING_SCROLL_WHEEL 175 int mLogMaxScrubSpeed; 176 #endif 177 178 AudacityProject *mProject; 179 180 DECLARE_EVENT_TABLE() 181 182 #ifdef USE_SCRUB_THREAD 183 // Course corrections in playback are done in a helper thread, unhindered by 184 // the complications of the main event dispatch loop 185 class ScrubPollerThread; 186 ScrubPollerThread *mpThread {}; 187 #endif 188 189 // Other periodic update of the UI must be done in the main thread, 190 // by this object which is driven by timer events. 191 class ScrubPoller; 192 std::unique_ptr<ScrubPoller> mPoller; 193 194 ScrubbingOptions mOptions; 195 double mMaxSpeed { 1.0 }; 196 197 bool mShowScrubbing { false }; 198 bool mMayDragToSeek{ false }; 199 }; 200 201 #endif 202