mirror of
https://github.com/cookiengineer/audacity
synced 2025-08-16 08:34:10 +02:00
Merge branch 'master' into scrubbing2
This commit is contained in:
commit
3347f2af70
@ -243,10 +243,31 @@ public:
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void SetScrollbar(int position, int thumbSize,
|
||||||
|
int range, int pageSize,
|
||||||
|
bool refresh = true) override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
DECLARE_EVENT_TABLE()
|
DECLARE_EVENT_TABLE()
|
||||||
};
|
};
|
||||||
|
|
||||||
|
void ScrollBar::SetScrollbar(int position, int thumbSize,
|
||||||
|
int range, int pageSize,
|
||||||
|
bool refresh)
|
||||||
|
{
|
||||||
|
// Mitigate flashing of scrollbars by refreshing only when something really changes.
|
||||||
|
|
||||||
|
auto changed =
|
||||||
|
position != GetThumbPosition() ||
|
||||||
|
thumbSize != GetThumbSize() ||
|
||||||
|
range != GetRange() ||
|
||||||
|
pageSize != GetPageSize();
|
||||||
|
if (!changed)
|
||||||
|
return;
|
||||||
|
|
||||||
|
wxScrollBar::SetScrollbar(position, thumbSize, range, pageSize, refresh);
|
||||||
|
}
|
||||||
|
|
||||||
BEGIN_EVENT_TABLE(ScrollBar, wxScrollBar)
|
BEGIN_EVENT_TABLE(ScrollBar, wxScrollBar)
|
||||||
EVT_SET_FOCUS(ScrollBar::OnSetFocus)
|
EVT_SET_FOCUS(ScrollBar::OnSetFocus)
|
||||||
END_EVENT_TABLE()
|
END_EVENT_TABLE()
|
||||||
@ -933,14 +954,18 @@ AudacityProject::AudacityProject(wxWindow * parent, wxWindowID id,
|
|||||||
mCursorOverlay = std::make_unique<EditCursorOverlay>(this);
|
mCursorOverlay = std::make_unique<EditCursorOverlay>(this);
|
||||||
|
|
||||||
#ifdef EXPERIMENTAL_SCRUBBING_BASIC
|
#ifdef EXPERIMENTAL_SCRUBBING_BASIC
|
||||||
// This must follow construction of *mIndicatorOverlay, because it must
|
|
||||||
// attach its timer event handler later (so that its handler is invoked
|
|
||||||
// earlier)
|
|
||||||
mScrubOverlay = std::make_unique<ScrubbingOverlay>(this);
|
mScrubOverlay = std::make_unique<ScrubbingOverlay>(this);
|
||||||
mScrubber = std::make_unique<Scrubber>(this);
|
mScrubber = std::make_unique<Scrubber>(this);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// This must follow construction of *mScrubOverlay, because it must
|
// More order dependencies here...
|
||||||
|
// This must follow construction of *mIndicatorOverlay, because it must
|
||||||
|
// attach its timer event handler later (so that its handler is invoked
|
||||||
|
// earlier)
|
||||||
|
mPlaybackScroller = std::make_unique<PlaybackScroller>(this);
|
||||||
|
|
||||||
|
// This must follow construction of *mPlaybackScroller,
|
||||||
|
// because it must
|
||||||
// attach its timer event handler later (so that its handler is invoked
|
// attach its timer event handler later (so that its handler is invoked
|
||||||
// earlier)
|
// earlier)
|
||||||
this->Connect(EVT_TRACK_PANEL_TIMER,
|
this->Connect(EVT_TRACK_PANEL_TIMER,
|
||||||
@ -1771,7 +1796,6 @@ void AudacityProject::FixScrollbars()
|
|||||||
|
|
||||||
mHsbar->SetScrollbar(scaledSbarH + offset, scaledSbarScreen, scaledSbarTotal,
|
mHsbar->SetScrollbar(scaledSbarH + offset, scaledSbarScreen, scaledSbarTotal,
|
||||||
scaledSbarScreen, TRUE);
|
scaledSbarScreen, TRUE);
|
||||||
mHsbar->Refresh();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Vertical scrollbar
|
// Vertical scrollbar
|
||||||
@ -1779,7 +1803,6 @@ void AudacityProject::FixScrollbars()
|
|||||||
panelHeight / mViewInfo.scrollStep,
|
panelHeight / mViewInfo.scrollStep,
|
||||||
totalHeight / mViewInfo.scrollStep,
|
totalHeight / mViewInfo.scrollStep,
|
||||||
panelHeight / mViewInfo.scrollStep, TRUE);
|
panelHeight / mViewInfo.scrollStep, TRUE);
|
||||||
mVsbar->Refresh();
|
|
||||||
|
|
||||||
if (refresh || (rescroll &&
|
if (refresh || (rescroll &&
|
||||||
(GetScreenEndTime() - mViewInfo.h) < mViewInfo.total)) {
|
(GetScreenEndTime() - mViewInfo.h) < mViewInfo.total)) {
|
||||||
@ -5315,3 +5338,46 @@ int AudacityProject::GetEstimatedRecordingMinsLeftOnDisk() {
|
|||||||
int iRecMins = (int)(dRecTime / 60.0);
|
int iRecMins = (int)(dRecTime / 60.0);
|
||||||
return iRecMins;
|
return iRecMins;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
AudacityProject::PlaybackScroller::PlaybackScroller(AudacityProject *project)
|
||||||
|
: mProject(project)
|
||||||
|
{
|
||||||
|
mProject->Connect(EVT_TRACK_PANEL_TIMER,
|
||||||
|
wxCommandEventHandler(PlaybackScroller::OnTimer),
|
||||||
|
NULL,
|
||||||
|
this);
|
||||||
|
}
|
||||||
|
|
||||||
|
AudacityProject::PlaybackScroller::~PlaybackScroller()
|
||||||
|
{
|
||||||
|
mProject->Disconnect(EVT_TRACK_PANEL_TIMER,
|
||||||
|
wxCommandEventHandler(PlaybackScroller::OnTimer),
|
||||||
|
NULL,
|
||||||
|
this);
|
||||||
|
}
|
||||||
|
|
||||||
|
void AudacityProject::PlaybackScroller::OnTimer(wxCommandEvent &event)
|
||||||
|
{
|
||||||
|
// Let other listeners get the notification
|
||||||
|
event.Skip();
|
||||||
|
|
||||||
|
#ifdef EXPERIMENTAL_SCRUBBING_SMOOTH_SCROLL
|
||||||
|
if (mActive && mProject->IsAudioActive())
|
||||||
|
{
|
||||||
|
// Pan the view, so that we center the play indicator.
|
||||||
|
|
||||||
|
ViewInfo &viewInfo = mProject->GetViewInfo();
|
||||||
|
TrackPanel *const trackPanel = mProject->GetTrackPanel();
|
||||||
|
const int posX = viewInfo.TimeToPosition(viewInfo.mRecentStreamTime);
|
||||||
|
int width;
|
||||||
|
trackPanel->GetTracksUsableArea(&width, NULL);
|
||||||
|
const int deltaX = posX - width / 2;
|
||||||
|
viewInfo.h =
|
||||||
|
viewInfo.OffsetTimeByPixels(viewInfo.h, deltaX, true);
|
||||||
|
if (!viewInfo.bScrollBeyondZero)
|
||||||
|
// Can't scroll too far left
|
||||||
|
viewInfo.h = std::max(0.0, viewInfo.h);
|
||||||
|
trackPanel->Refresh(false);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
@ -720,6 +720,28 @@ public:
|
|||||||
const Scrubber &GetScrubber() const { return *mScrubber; }
|
const Scrubber &GetScrubber() const { return *mScrubber; }
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
class PlaybackScroller final : public wxEvtHandler
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
explicit PlaybackScroller(AudacityProject *project);
|
||||||
|
~PlaybackScroller();
|
||||||
|
|
||||||
|
void Activate(bool active)
|
||||||
|
{
|
||||||
|
mActive = active;
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
void OnTimer(wxCommandEvent &event);
|
||||||
|
|
||||||
|
AudacityProject *mProject;
|
||||||
|
bool mActive { false };
|
||||||
|
};
|
||||||
|
std::unique_ptr<PlaybackScroller> mPlaybackScroller;
|
||||||
|
|
||||||
|
public:
|
||||||
|
PlaybackScroller &GetPlaybackScroller() { return *mPlaybackScroller; }
|
||||||
|
|
||||||
DECLARE_EVENT_TABLE()
|
DECLARE_EVENT_TABLE()
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -5901,16 +5901,26 @@ void TrackPanel::OnMouseEvent(wxMouseEvent & event)
|
|||||||
ReleaseMouse();
|
ReleaseMouse();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (event.Leaving() && !event.ButtonIsDown(wxMOUSE_BTN_ANY))
|
if (event.Leaving())
|
||||||
{
|
{
|
||||||
|
|
||||||
// PRL: was this test really needed? It interfered with my refactoring
|
// PRL: was this test really needed? It interfered with my refactoring
|
||||||
// that tried to eliminate those enum values.
|
// that tried to eliminate those enum values.
|
||||||
// I think it was never true, that mouse capture was pan or gain sliding,
|
// I think it was never true, that mouse capture was pan or gain sliding,
|
||||||
// but no mouse button was down.
|
// but no mouse button was down.
|
||||||
// if (mMouseCapture != IsPanSliding && mMouseCapture != IsGainSliding)
|
// if (mMouseCapture != IsPanSliding && mMouseCapture != IsGainSliding)
|
||||||
{
|
|
||||||
|
auto buttons =
|
||||||
|
// Bug 1325: button state in Leaving events is unreliable on Mac.
|
||||||
|
// Poll the global state instead.
|
||||||
|
// event.ButtonIsDown(wxMOUSE_BTN_ANY);
|
||||||
|
::wxGetMouseState().ButtonIsDown(wxMOUSE_BTN_ANY);
|
||||||
|
|
||||||
|
if(!buttons) {
|
||||||
SetCapturedTrack(NULL);
|
SetCapturedTrack(NULL);
|
||||||
|
|
||||||
#if defined(__WXMAC__)
|
#if defined(__WXMAC__)
|
||||||
|
|
||||||
// We must install the cursor ourselves since the window under
|
// We must install the cursor ourselves since the window under
|
||||||
// the mouse is no longer this one and wx2.8.12 makes that check.
|
// the mouse is no longer this one and wx2.8.12 makes that check.
|
||||||
// Should re-evaluate with wx3.
|
// Should re-evaluate with wx3.
|
||||||
|
@ -738,16 +738,24 @@ void ControlToolBar::OnKeyEvent(wxKeyEvent & event)
|
|||||||
|
|
||||||
void ControlToolBar::OnPlay(wxCommandEvent & WXUNUSED(evt))
|
void ControlToolBar::OnPlay(wxCommandEvent & WXUNUSED(evt))
|
||||||
{
|
{
|
||||||
if (!CanStopAudioStream())
|
auto doubleClicked = mPlay->IsDoubleClicked();
|
||||||
return;
|
mPlay->ClearDoubleClicked();
|
||||||
|
|
||||||
StopPlaying();
|
auto p = GetActiveProject();
|
||||||
|
|
||||||
AudacityProject *p = GetActiveProject();
|
if (doubleClicked)
|
||||||
if (p) p->TP_DisplaySelection();
|
p->GetPlaybackScroller().Activate(true);
|
||||||
|
else {
|
||||||
|
if (!CanStopAudioStream())
|
||||||
|
return;
|
||||||
|
|
||||||
PlayDefault();
|
StopPlaying();
|
||||||
UpdateStatusBar(GetActiveProject());
|
|
||||||
|
if (p) p->TP_DisplaySelection();
|
||||||
|
|
||||||
|
PlayDefault();
|
||||||
|
UpdateStatusBar(p);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void ControlToolBar::OnStop(wxCommandEvent & WXUNUSED(evt))
|
void ControlToolBar::OnStop(wxCommandEvent & WXUNUSED(evt))
|
||||||
@ -778,9 +786,11 @@ void ControlToolBar::StopPlaying(bool stopStream /* = true*/)
|
|||||||
{
|
{
|
||||||
AudacityProject *project = GetActiveProject();
|
AudacityProject *project = GetActiveProject();
|
||||||
|
|
||||||
if(project)
|
if(project) {
|
||||||
|
project->GetPlaybackScroller().Activate(false);
|
||||||
// Let scrubbing code do some appearance change
|
// Let scrubbing code do some appearance change
|
||||||
project->GetScrubber().StopScrubbing();
|
project->GetScrubber().StopScrubbing();
|
||||||
|
}
|
||||||
|
|
||||||
if (!CanStopAudioStream())
|
if (!CanStopAudioStream())
|
||||||
return;
|
return;
|
||||||
|
@ -474,11 +474,24 @@ void TranscriptionToolBar::PlayAtSpeed(bool looped, bool cutPreview)
|
|||||||
// Come here from button clicks only
|
// Come here from button clicks only
|
||||||
void TranscriptionToolBar::OnPlaySpeed(wxCommandEvent & WXUNUSED(event))
|
void TranscriptionToolBar::OnPlaySpeed(wxCommandEvent & WXUNUSED(event))
|
||||||
{
|
{
|
||||||
// Let control have precedence over shift
|
auto button = mButtons[TTB_PlaySpeed];
|
||||||
const bool cutPreview = mButtons[TTB_PlaySpeed]->WasControlDown();
|
|
||||||
const bool looped = !cutPreview &&
|
auto doubleClicked = button->IsDoubleClicked();
|
||||||
mButtons[TTB_PlaySpeed]->WasShiftDown();
|
button->ClearDoubleClicked();
|
||||||
PlayAtSpeed(looped, cutPreview);
|
|
||||||
|
if (doubleClicked) {
|
||||||
|
GetActiveProject()->GetPlaybackScroller().Activate(true);
|
||||||
|
|
||||||
|
// Pop up the button
|
||||||
|
SetButton(false, button);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
// Let control have precedence over shift
|
||||||
|
const bool cutPreview = mButtons[TTB_PlaySpeed]->WasControlDown();
|
||||||
|
const bool looped = !cutPreview &&
|
||||||
|
button->WasShiftDown();
|
||||||
|
PlayAtSpeed(looped, cutPreview);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void TranscriptionToolBar::OnSpeedSlider(wxCommandEvent& WXUNUSED(event))
|
void TranscriptionToolBar::OnSpeedSlider(wxCommandEvent& WXUNUSED(event))
|
||||||
|
@ -200,7 +200,7 @@ void Scrubber::MarkScrubStart(
|
|||||||
// needed for the decision to start scrubbing later when handling
|
// needed for the decision to start scrubbing later when handling
|
||||||
// drag events.
|
// drag events.
|
||||||
#ifdef EXPERIMENTAL_SCRUBBING_SMOOTH_SCROLL
|
#ifdef EXPERIMENTAL_SCRUBBING_SMOOTH_SCROLL
|
||||||
mSmoothScrollingScrub = smoothScrolling;
|
SetScrollScrubbing (smoothScrolling);
|
||||||
#endif
|
#endif
|
||||||
mAlwaysSeeking = alwaysSeeking;
|
mAlwaysSeeking = alwaysSeeking;
|
||||||
mScrubStartPosition = xx;
|
mScrubStartPosition = xx;
|
||||||
@ -356,25 +356,6 @@ void Scrubber::ContinueScrubbing()
|
|||||||
if (mScrubSpeedDisplayCountdown > 0)
|
if (mScrubSpeedDisplayCountdown > 0)
|
||||||
--mScrubSpeedDisplayCountdown;
|
--mScrubSpeedDisplayCountdown;
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef EXPERIMENTAL_SCRUBBING_SMOOTH_SCROLL
|
|
||||||
if (mSmoothScrollingScrub) {
|
|
||||||
// Pan the view, so that we center the play indicator.
|
|
||||||
|
|
||||||
ViewInfo &viewInfo = mProject->GetViewInfo();
|
|
||||||
TrackPanel *const trackPanel = mProject->GetTrackPanel();
|
|
||||||
const int posX = viewInfo.TimeToPosition(viewInfo.mRecentStreamTime);
|
|
||||||
int width;
|
|
||||||
trackPanel->GetTracksUsableArea(&width, NULL);
|
|
||||||
const int deltaX = posX - width / 2;
|
|
||||||
viewInfo.h =
|
|
||||||
viewInfo.OffsetTimeByPixels(viewInfo.h, deltaX, true);
|
|
||||||
if (!viewInfo.bScrollBeyondZero)
|
|
||||||
// Can't scroll too far left
|
|
||||||
viewInfo.h = std::max(0.0, viewInfo.h);
|
|
||||||
trackPanel->Refresh(false);
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void Scrubber::StopScrubbing()
|
void Scrubber::StopScrubbing()
|
||||||
@ -382,7 +363,7 @@ void Scrubber::StopScrubbing()
|
|||||||
UncheckAllMenuItems();
|
UncheckAllMenuItems();
|
||||||
|
|
||||||
mScrubStartPosition = -1;
|
mScrubStartPosition = -1;
|
||||||
mSmoothScrollingScrub = false;
|
SetScrollScrubbing (false);
|
||||||
|
|
||||||
if (!IsScrubbing())
|
if (!IsScrubbing())
|
||||||
{
|
{
|
||||||
@ -393,6 +374,12 @@ void Scrubber::StopScrubbing()
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Scrubber::SetScrollScrubbing(bool scrollScrubbing)
|
||||||
|
{
|
||||||
|
mSmoothScrollingScrub = scrollScrubbing;
|
||||||
|
mProject->GetPlaybackScroller().Activate(scrollScrubbing);
|
||||||
|
}
|
||||||
|
|
||||||
bool Scrubber::IsScrubbing() const
|
bool Scrubber::IsScrubbing() const
|
||||||
{
|
{
|
||||||
if (mScrubToken <= 0)
|
if (mScrubToken <= 0)
|
||||||
@ -403,6 +390,7 @@ bool Scrubber::IsScrubbing() const
|
|||||||
const_cast<Scrubber&>(*this).mScrubToken = -1;
|
const_cast<Scrubber&>(*this).mScrubToken = -1;
|
||||||
const_cast<Scrubber&>(*this).mScrubStartPosition = -1;
|
const_cast<Scrubber&>(*this).mScrubStartPosition = -1;
|
||||||
#ifdef EXPERIMENTAL_SCRUBBING_SMOOTH_SCROLL
|
#ifdef EXPERIMENTAL_SCRUBBING_SMOOTH_SCROLL
|
||||||
|
// Don't call SetScrollScrubbing
|
||||||
const_cast<Scrubber&>(*this).mSmoothScrollingScrub = false;
|
const_cast<Scrubber&>(*this).mSmoothScrollingScrub = false;
|
||||||
#endif
|
#endif
|
||||||
return false;
|
return false;
|
||||||
@ -557,7 +545,6 @@ void ScrubbingOverlay::Draw
|
|||||||
dc.DrawText(mLastScrubSpeedText, mLastScrubRect.GetX(), mLastScrubRect.GetY());
|
dc.DrawText(mLastScrubSpeedText, mLastScrubRect.GetX(), mLastScrubRect.GetY());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void ScrubbingOverlay::OnTimer(wxCommandEvent &event)
|
void ScrubbingOverlay::OnTimer(wxCommandEvent &event)
|
||||||
{
|
{
|
||||||
// Let other listeners get the notification
|
// Let other listeners get the notification
|
||||||
@ -666,7 +653,7 @@ void Scrubber::DoScrub(bool scroll, bool seek)
|
|||||||
MarkScrubStart(xx, scroll, seek);
|
MarkScrubStart(xx, scroll, seek);
|
||||||
}
|
}
|
||||||
else if(!match) {
|
else if(!match) {
|
||||||
mSmoothScrollingScrub = scroll;
|
SetScrollScrubbing(scroll);
|
||||||
mAlwaysSeeking = seek;
|
mAlwaysSeeking = seek;
|
||||||
UncheckAllMenuItems();
|
UncheckAllMenuItems();
|
||||||
CheckMenuItem();
|
CheckMenuItem();
|
||||||
|
@ -54,8 +54,11 @@ public:
|
|||||||
bool HasStartedScrubbing() const
|
bool HasStartedScrubbing() const
|
||||||
{ return GetScrubStartPosition() >= 0; }
|
{ return GetScrubStartPosition() >= 0; }
|
||||||
bool IsScrubbing() const;
|
bool IsScrubbing() const;
|
||||||
|
|
||||||
bool IsScrollScrubbing() const // If true, implies HasStartedScrubbing()
|
bool IsScrollScrubbing() const // If true, implies HasStartedScrubbing()
|
||||||
{ return mSmoothScrollingScrub; }
|
{ return mSmoothScrollingScrub; }
|
||||||
|
void SetScrollScrubbing(bool scrollScrubbing);
|
||||||
|
|
||||||
bool IsAlwaysSeeking() const
|
bool IsAlwaysSeeking() const
|
||||||
{ return mAlwaysSeeking; }
|
{ return mAlwaysSeeking; }
|
||||||
|
|
||||||
|
@ -407,6 +407,8 @@ void AButton::OnMouseEvent(wxMouseEvent & event)
|
|||||||
if (mEnabled && event.IsButton()) {
|
if (mEnabled && event.IsButton()) {
|
||||||
if (event.ButtonIsDown(wxMOUSE_BTN_ANY)) {
|
if (event.ButtonIsDown(wxMOUSE_BTN_ANY)) {
|
||||||
mIsClicking = true;
|
mIsClicking = true;
|
||||||
|
if (event.ButtonDClick())
|
||||||
|
mIsDoubleClicked = true;
|
||||||
if( !HasCapture() )
|
if( !HasCapture() )
|
||||||
CaptureMouse();
|
CaptureMouse();
|
||||||
}
|
}
|
||||||
|
@ -109,6 +109,11 @@ class AButton final : public wxWindow {
|
|||||||
bool WasControlDown(); // returns true if control was held down
|
bool WasControlDown(); // returns true if control was held down
|
||||||
// the last time the button was clicked
|
// the last time the button was clicked
|
||||||
bool IsDown(){ return mButtonIsDown;}
|
bool IsDown(){ return mButtonIsDown;}
|
||||||
|
|
||||||
|
// Double click is detected, but not automatically cleared.
|
||||||
|
bool IsDoubleClicked() const { return mIsDoubleClicked; }
|
||||||
|
void ClearDoubleClicked() { mIsDoubleClicked = false; }
|
||||||
|
|
||||||
void SetButtonToggles( bool toggler ){ mToggle = toggler;}
|
void SetButtonToggles( bool toggler ){ mToggle = toggler;}
|
||||||
void Toggle(){ mButtonIsDown ? PopUp() : PushDown();}
|
void Toggle(){ mButtonIsDown ? PopUp() : PushDown();}
|
||||||
void Click();
|
void Click();
|
||||||
@ -157,6 +162,7 @@ class AButton final : public wxWindow {
|
|||||||
bool mIsClicking;
|
bool mIsClicking;
|
||||||
bool mEnabled;
|
bool mEnabled;
|
||||||
bool mUseDisabledAsDownHiliteImage;
|
bool mUseDisabledAsDownHiliteImage;
|
||||||
|
bool mIsDoubleClicked {};
|
||||||
|
|
||||||
struct ImageArr { ImageRoll mArr[4]; };
|
struct ImageArr { ImageRoll mArr[4]; };
|
||||||
std::vector<ImageArr> mImages;
|
std::vector<ImageArr> mImages;
|
||||||
|
@ -85,6 +85,7 @@ array of Ruler::Label.
|
|||||||
#include "../tracks/ui/Scrubbing.h"
|
#include "../tracks/ui/Scrubbing.h"
|
||||||
|
|
||||||
//#define SCRUB_ABOVE
|
//#define SCRUB_ABOVE
|
||||||
|
#define RULER_DOUBLE_CLICK
|
||||||
|
|
||||||
using std::min;
|
using std::min;
|
||||||
using std::max;
|
using std::max;
|
||||||
@ -2024,6 +2025,9 @@ void AdornedRulerPanel::OnCapture(wxCommandEvent & evt)
|
|||||||
// if recording is initiated by a modal window (Timer Record).
|
// if recording is initiated by a modal window (Timer Record).
|
||||||
SetCursor(mCursorDefault);
|
SetCursor(mCursorDefault);
|
||||||
mIsRecording = true;
|
mIsRecording = true;
|
||||||
|
|
||||||
|
// The quick play indicator is useless during recording
|
||||||
|
HideQuickPlayIndicator();
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
SetCursor(mCursorHand);
|
SetCursor(mCursorHand);
|
||||||
@ -2364,7 +2368,15 @@ void AdornedRulerPanel::OnMouseEvents(wxMouseEvent &evt)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef RULER_DOUBLE_CLICK
|
||||||
|
if (evt.LeftDClick()) {
|
||||||
|
mDoubleClick = true;
|
||||||
|
HandleQPDoubleClick(evt, mousePosX);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
#endif
|
||||||
if (evt.LeftDown()) {
|
if (evt.LeftDown()) {
|
||||||
|
mDoubleClick = false;
|
||||||
HandleQPClick(evt, mousePosX);
|
HandleQPClick(evt, mousePosX);
|
||||||
HandleQPDrag(evt, mousePosX);
|
HandleQPDrag(evt, mousePosX);
|
||||||
}
|
}
|
||||||
@ -2379,6 +2391,11 @@ void AdornedRulerPanel::OnMouseEvents(wxMouseEvent &evt)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void AdornedRulerPanel::HandleQPDoubleClick(wxMouseEvent &evt, wxCoord mousePosX)
|
||||||
|
{
|
||||||
|
mProject->GetPlaybackScroller().Activate(true);
|
||||||
|
}
|
||||||
|
|
||||||
void AdornedRulerPanel::HandleQPClick(wxMouseEvent &evt, wxCoord mousePosX)
|
void AdornedRulerPanel::HandleQPClick(wxMouseEvent &evt, wxCoord mousePosX)
|
||||||
{
|
{
|
||||||
// Temporarily unlock locked play region
|
// Temporarily unlock locked play region
|
||||||
@ -2512,6 +2529,9 @@ void AdornedRulerPanel::HandleQPDrag(wxMouseEvent &event, wxCoord mousePosX)
|
|||||||
|
|
||||||
void AdornedRulerPanel::HandleQPRelease(wxMouseEvent &evt)
|
void AdornedRulerPanel::HandleQPRelease(wxMouseEvent &evt)
|
||||||
{
|
{
|
||||||
|
if (mDoubleClick)
|
||||||
|
return;
|
||||||
|
|
||||||
HideQuickPlayIndicator();
|
HideQuickPlayIndicator();
|
||||||
|
|
||||||
if (HasCapture())
|
if (HasCapture())
|
||||||
@ -2552,6 +2572,28 @@ void AdornedRulerPanel::HandleQPRelease(wxMouseEvent &evt)
|
|||||||
ClearPlayRegion();
|
ClearPlayRegion();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
StartQPPlay(evt.ShiftDown(), evt.ControlDown());
|
||||||
|
|
||||||
|
mMouseEventState = mesNone;
|
||||||
|
mIsDragging = false;
|
||||||
|
mLeftDownClick = -1;
|
||||||
|
|
||||||
|
if (mPlayRegionLock) {
|
||||||
|
// Restore Locked Play region
|
||||||
|
SetPlayRegion(mOldPlayRegionStart, mOldPlayRegionEnd);
|
||||||
|
mProject->OnLockPlayRegion();
|
||||||
|
// and release local lock
|
||||||
|
mPlayRegionLock = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void AdornedRulerPanel::StartQPPlay(bool looped, bool cutPreview)
|
||||||
|
{
|
||||||
|
const double t0 = mTracks->GetStartTime();
|
||||||
|
const double t1 = mTracks->GetEndTime();
|
||||||
|
const double sel0 = mProject->GetSel0();
|
||||||
|
const double sel1 = mProject->GetSel1();
|
||||||
|
|
||||||
// Start / Restart playback on left click.
|
// Start / Restart playback on left click.
|
||||||
bool startPlaying = (mPlayRegionStart >= 0);
|
bool startPlaying = (mPlayRegionStart >= 0);
|
||||||
|
|
||||||
@ -2562,7 +2604,7 @@ void AdornedRulerPanel::HandleQPRelease(wxMouseEvent &evt)
|
|||||||
bool loopEnabled = true;
|
bool loopEnabled = true;
|
||||||
double start, end;
|
double start, end;
|
||||||
|
|
||||||
if ((mPlayRegionEnd - mPlayRegionStart == 0.0) && evt.ShiftDown()) {
|
if ((mPlayRegionEnd - mPlayRegionStart == 0.0) && looped) {
|
||||||
// Loop play a point will loop either a selection or the project.
|
// Loop play a point will loop either a selection or the project.
|
||||||
if ((mPlayRegionStart > sel0) && (mPlayRegionStart < sel1)) {
|
if ((mPlayRegionStart > sel0) && (mPlayRegionStart < sel1)) {
|
||||||
// we are in a selection, so use the selection
|
// we are in a selection, so use the selection
|
||||||
@ -2582,15 +2624,15 @@ void AdornedRulerPanel::HandleQPRelease(wxMouseEvent &evt)
|
|||||||
loopEnabled = ((end - start) > 0.001)? true : false;
|
loopEnabled = ((end - start) > 0.001)? true : false;
|
||||||
|
|
||||||
AudioIOStartStreamOptions options(mProject->GetDefaultPlayOptions());
|
AudioIOStartStreamOptions options(mProject->GetDefaultPlayOptions());
|
||||||
options.playLooped = (loopEnabled && evt.ShiftDown());
|
options.playLooped = (loopEnabled && looped);
|
||||||
|
|
||||||
if (!evt.ControlDown())
|
if (!cutPreview)
|
||||||
options.pStartTime = &mPlayRegionStart;
|
options.pStartTime = &mPlayRegionStart;
|
||||||
else
|
else
|
||||||
options.timeTrack = NULL;
|
options.timeTrack = NULL;
|
||||||
|
|
||||||
ControlToolBar::PlayAppearance appearance =
|
ControlToolBar::PlayAppearance appearance =
|
||||||
evt.ControlDown() ? ControlToolBar::PlayAppearance::CutPreview
|
cutPreview ? ControlToolBar::PlayAppearance::CutPreview
|
||||||
: options.playLooped ? ControlToolBar::PlayAppearance::Looped
|
: options.playLooped ? ControlToolBar::PlayAppearance::Looped
|
||||||
: ControlToolBar::PlayAppearance::Straight;
|
: ControlToolBar::PlayAppearance::Straight;
|
||||||
ctb->PlayPlayRegion((SelectedRegion(start, end)),
|
ctb->PlayPlayRegion((SelectedRegion(start, end)),
|
||||||
@ -2603,18 +2645,6 @@ void AdornedRulerPanel::HandleQPRelease(wxMouseEvent &evt)
|
|||||||
mPlayRegionEnd = end;
|
mPlayRegionEnd = end;
|
||||||
Refresh();
|
Refresh();
|
||||||
}
|
}
|
||||||
|
|
||||||
mMouseEventState = mesNone;
|
|
||||||
mIsDragging = false;
|
|
||||||
mLeftDownClick = -1;
|
|
||||||
|
|
||||||
if (mPlayRegionLock) {
|
|
||||||
// Restore Locked Play region
|
|
||||||
SetPlayRegion(mOldPlayRegionStart, mOldPlayRegionEnd);
|
|
||||||
mProject->OnLockPlayRegion();
|
|
||||||
// and release local lock
|
|
||||||
mPlayRegionLock = false;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void AdornedRulerPanel::UpdateStatusBarAndTooltips(StatusChoice choice)
|
void AdornedRulerPanel::UpdateStatusBarAndTooltips(StatusChoice choice)
|
||||||
|
@ -342,9 +342,11 @@ private:
|
|||||||
void OnSize(wxSizeEvent &evt);
|
void OnSize(wxSizeEvent &evt);
|
||||||
void UpdateRects();
|
void UpdateRects();
|
||||||
void OnMouseEvents(wxMouseEvent &evt);
|
void OnMouseEvents(wxMouseEvent &evt);
|
||||||
|
void HandleQPDoubleClick(wxMouseEvent &event, wxCoord mousePosX);
|
||||||
void HandleQPClick(wxMouseEvent &event, wxCoord mousePosX);
|
void HandleQPClick(wxMouseEvent &event, wxCoord mousePosX);
|
||||||
void HandleQPDrag(wxMouseEvent &event, wxCoord mousePosX);
|
void HandleQPDrag(wxMouseEvent &event, wxCoord mousePosX);
|
||||||
void HandleQPRelease(wxMouseEvent &event);
|
void HandleQPRelease(wxMouseEvent &event);
|
||||||
|
void StartQPPlay(bool looped, bool cutPreview);
|
||||||
|
|
||||||
static inline bool IsButton(StatusChoice choice)
|
static inline bool IsButton(StatusChoice choice)
|
||||||
{
|
{
|
||||||
@ -488,6 +490,8 @@ private:
|
|||||||
mutable int mButtonFontSize { -1 };
|
mutable int mButtonFontSize { -1 };
|
||||||
mutable wxFont mButtonFont;
|
mutable wxFont mButtonFont;
|
||||||
|
|
||||||
|
bool mDoubleClick {};
|
||||||
|
|
||||||
DECLARE_EVENT_TABLE()
|
DECLARE_EVENT_TABLE()
|
||||||
};
|
};
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user