26#include <wx/tooltip.h>
34#include "../images/Cursors.h"
64#include <wx/dcclient.h>
72#define SELECT_TOLERANCE_PIXEL 4
74#define PLAY_REGION_TRIANGLE_SIZE 6
75#define PLAY_REGION_RECT_WIDTH 1
76#define PLAY_REGION_RECT_HEIGHT 3
77#define PLAY_REGION_GLOBAL_OFFSET_Y 7
98 return ((width / 2) * 3) / 2;
105 (((height) * 2) / 3) * 2
136 if (oldState.
mX != newState.
mX)
163 const auto pos =
event.event.GetPosition();
172 return viewInfo.PositionToTime(
mX, viewInfo.GetLeftOffset());
184 auto saveMe =
ruler.Target();
186 const auto startTime =
Time(project);
187 ruler.StartQPPlay(!event.ShiftDown(),
false, &startTime);
216 size_t numGuides = 1)
227 const auto message =
XO(
"Click and drag to define a looping region.");
244 mX =
event.event.m_x;
281 auto &playRegion = viewInfo.playRegion;
297 auto &playRegion = viewInfo.playRegion;
300 playRegion.SetActive(
false);
311 auto identity = [](
auto x){
return x; };
329 bool isSnapped =
ruler.mIsSnapped[ii];
331 ?
ruler.mQuickPlayPos[ii]
332 :
ruler.mQuickPlayPosUnsnapped[ii];
338 for (
size_t ii = 0; ii <
ruler.mNumGuides; ++ii)
339 if (
ruler.mIsSnapped[ii]) {
340 double time0 =
ruler.mQuickPlayPos[ii];
341 double delta = time0 -
ruler.mQuickPlayPosUnsnapped[ii];
342 double time1 =
ruler.mQuickPlayPosUnsnapped[1 - ii] + delta;
344 return { time1, time0 };
346 return { time0, time1 };
349 return {
ruler.mQuickPlayPos[0],
ruler.mQuickPlayPos[1] };
355 std::fill(
ruler.mIsSnapped,
ruler.mIsSnapped +
ruler.mNumGuides,
false );
369 auto &playRegion = viewInfo.playRegion;
371 mOldStart = playRegion.GetLastActiveStart();
372 mOldEnd = playRegion.GetLastActiveEnd();
374 playRegion.SetActive(
true);
456 { std::make_shared<ScrubbingRulerOverlay>(*
this) };
479 return &
Get( *mPartner.mProject );
484 const auto project = mPartner.mProject;
486 auto ruler = GetRuler();
488 bool scrubbing = (scrubber.IsScrubbing()
489 && !scrubber.IsSpeedPlaying()
490 && !scrubber.IsKeyboardScrubbing());
495 mNewQPIndicatorPos = -1;
499 std::max(
ruler->mTracks->GetEndTime(), selectedRegion.t1());
504 mNewIndicatorSnapped = -1;
506 mNewIndicatorSnapped == -1 && ii <
ruler->mNumGuides; ++ii) {
507 if (
ruler->mIsSnapped[ii]) {
508 mNewIndicatorSnapped = ii;
511 mNewQPIndicatorPos =
ruler->Time2Pos(
512 ruler->mQuickPlayPos[std::max(0, mNewIndicatorSnapped)]);
517 !
ruler->IsMouseCaptured() &&
518 (
ruler->LastCell() ==
ruler->mScrubbingCell ||
519 (scrubber.HasMark()));
520 mNewSeek = mNewScrub &&
521 (scrubber.Seeks() || scrubber.TemporarilySeeks());
531std::pair<wxRect, bool>
536 const auto x = mOldQPIndicatorPos;
543 const int indsize = width / 2;
545 auto xx = x - indsize;
550 GetRuler()->GetSize().GetHeight() },
551 (x != mNewQPIndicatorPos
552 || (mOldScrub != mNewScrub)
553 || (mOldSeek != mNewSeek) )
557 return { {}, mNewQPIndicatorPos >= 0 };
563 mOldQPIndicatorPos = mNewQPIndicatorPos;
564 mOldScrub = mNewScrub;
566 if (mOldQPIndicatorPos >= 0) {
567 auto ruler = GetRuler();
569 ruler->DoDrawScrubIndicator(
570 &dc, mOldQPIndicatorPos, width, mOldScrub, mOldSeek);
596 const auto ruler = &
Get( *project );
600 mNewPreviewingScrub =
602 !scrubber.IsScrubbing();
605std::pair<wxRect, bool>
610 wxRect rect(mOldQPIndicatorPos, 0, 1,
size.GetHeight());
611 return std::make_pair(
613 (mOldQPIndicatorPos != mPartner->mNewQPIndicatorPos ||
614 mOldIndicatorSnapped != mPartner->mNewIndicatorSnapped ||
615 mOldPreviewingScrub != mNewPreviewingScrub)
622 mOldQPIndicatorPos = mPartner->mNewQPIndicatorPos;
623 mOldIndicatorSnapped = mPartner->mNewIndicatorSnapped;
624 mOldPreviewingScrub = mNewPreviewingScrub;
626 if (mOldQPIndicatorPos >= 0) {
627 if (!mOldPreviewingScrub && mOldIndicatorSnapped < 0) {
631 pHandle !=
nullptr && pHandle->
Clicked())
638 : (mOldIndicatorSnapped >= 0)
643 auto pCellularPanel =
dynamic_cast<CellularPanel*
>( &panel );
644 if ( !pCellularPanel ) {
650 const auto pTrackView =
dynamic_cast<TrackView*
>(&cell);
712 , mMenuChoice{ menuChoice }
722 if (mParent->mTimelineToolTip)
723 tooltip =
XO(
"Timeline actions disabled during recording");
725 static wxCursor cursor{ wxCURSOR_DEFAULT };
737 mParent->ShowContextMenu(mMenuChoice, pPosition);
746#undef QUICK_PLAY_HANDLE
747#ifdef QUICK_PLAY_HANDLE
770 wxWindow *pParent)
override;
779 MakeCursor(wxCURSOR_HAND, RearrangeCursorXpm, 16, 16);
790 mParent->mQuickPlayOffset[0] = 0;
791 mParent->mQuickPlayOffset[1] = 0;
798 const auto time =
Time(project);
800 mParent->mQuickPlayOffset[0] = playRegion.GetStart() - time;
801 mParent->mQuickPlayOffset[1] = playRegion.GetEnd() - time;
811 playRegion.
SetTimes(times.first, times.second);
841 playRegion.SetEnd(time);
880 auto width = viewInfo.GetTracksUsableWidth();
881 return viewInfo.GetLeftOffset()
888 auto width = viewInfo.GetTracksUsableWidth();
889 auto fraction = (xx - viewInfo.GetLeftOffset()) /
double(width);
890 return std::max(0.0,
std::min(1.0, fraction));
899 : mpParent{ &parent }
906 if (oldState.
mX != newState.
mX)
911 static std::shared_ptr<PlayheadHandle>
916 .IsTransportingPinned() &&
921 return std::make_shared<PlayheadHandle>( parent, xx );
930 if (event.
event.LeftDClick()) {
939 if (!event.
event.LeftIsDown())
959 mpParent->SetNumGuides(1);
960 static wxCursor cursor{ wxCURSOR_SIZEWE };
962 XO(
"Click and drag to adjust, double-click to reset" ),
966 XO(
"Record/Play head" )
992 double mOrigPreference {};
1005 std::vector<UIHandlePtr>
HitTest(
1014#ifdef QUICK_PLAY_HANDLE
1015 if (
auto ptr = mHolder.lock())
1016 return ptr->Clicked();
1021#ifdef QUICK_PLAY_HANDLE
1022 std::weak_ptr<QPHandle> mHolder;
1037 mParent->CreateOverlays();
1039 std::vector<UIHandlePtr> results;
1040 auto xx = state.
state.m_x;
1042#ifdef EXPERIMENTAL_DRAGGABLE_PLAY_HEAD
1046 auto result = PlayheadHandle::HitTest( pProject, *mParent, xx );
1049 results.push_back( result );
1055 if (!mParent->mIsRecording) {
1056 mParent->UpdateQuickPlayPos( xx );
1059 auto result = std::make_shared<QPHandle>( mParent, xx );
1061 results.push_back( result );
1066 bool hitLeft =
false;
1069 mParent->IsWithinMarker(xx, playRegion.GetLastActiveStart())) ||
1070 mParent->IsWithinMarker(xx, playRegion.GetLastActiveEnd()))
1073 std::make_shared<ResizePlayRegionHandle>( mParent, xx, hitLeft );
1075 results.push_back(result);
1080 if (
auto time = mParent->Pos2Time(xx);
1081 playRegion.Active() &&
1082 time >= playRegion.GetStart() &&
1083 time <= playRegion.GetEnd())
1086 std::make_shared<MovePlayRegionHandle>( mParent, xx );
1088 results.push_back(result);
1093 auto result = std::make_shared<NewPlayRegionHandle>( mParent, xx );
1095 results.push_back(result);
1120 scrubber.CanScrub() &&
1126 if (!scrubber.HasMark()) {
1128 scrubber.MarkScrubStart(
1153 wxWindow *pParent)
override {
1186 std::vector<UIHandlePtr>
HitTest(
1196 if (
auto ptr =
mHolder.lock())
1197 return ptr->Clicked();
1210 mParent->CreateOverlays();
1212 std::vector<UIHandlePtr> results;
1215 if (!mParent->mIsRecording) {
1216 auto xx = state.
state.m_x;
1217 mParent->UpdateQuickPlayPos( xx );
1218 auto result = std::make_shared<ScrubbingHandle>( mParent, xx );
1220 results.push_back( result );
1227AttachedWindows::RegisteredFactory
sKey{
1256 pPanel->wxWindow::Destroy();
1270 SetLayoutDirection(wxLayout_LeftToRight);
1272 mQPCell = std::make_shared<QPCell>(
this );
1280 SetBackgroundStyle(wxBG_STYLE_PAINT);
1289 mOuter = GetClientRect();
1305 wxToolTip::Enable(
true);
1331 CellularPanel::Refresh( eraseBackground, rect );
1350#ifdef EXPERIMENTAL_SCROLLING_LIMITS
1351#ifdef EXPERIMENTAL_TWO_TONE_TIME_RULER
1384 wxPoint position( 1, 0 );
1389 pGrabber->SetPosition( position );
1396 auto buttonMaker = [&]
1397 (wxWindowID
id,
teBmps bitmap,
bool toggle)
1402 bmpRecoloredUpSmall, bmpRecoloredDownSmall,
1403 bmpRecoloredUpHiliteSmall, bmpRecoloredHiliteSmall,
1404 bitmap, bitmap, bitmap,
1405 id, position, toggle,
size
1408 position.x +=
size.GetWidth();
1415 bmpRecoloredUpSmall, bmpRecoloredDownSmall,
1416 bmpRecoloredUpHiliteSmall, bmpRecoloredHiliteSmall,
1418 bmpRecordPointer, bmpRecordPointer, bmpRecordPointer,
1422 bmpRecoloredUpSmall, bmpRecoloredDownSmall,
1423 bmpRecoloredUpHiliteSmall, bmpRecoloredHiliteSmall,
1425 bmpRecordPointerPinned, bmpRecordPointerPinned, bmpRecordPointerPinned,
1429 bmpRecoloredUpSmall, bmpRecoloredDownSmall,
1430 bmpRecoloredUpHiliteSmall, bmpRecoloredHiliteSmall,
1432 bmpPlayPointer, bmpPlayPointer, bmpPlayPointer,
1447 if(scrubber.Seeks())
1452 return XO(
"Click or drag to begin Seek");
1458 return XO(
"Click or drag to begin Scrub");
1464 return XO(
"Click & move to Scrub. Click & drag to Seek.");
1469 const Scrubber &scrubber,
bool clicked)
1472 if(scrubber.
Seeks())
1477 return XO(
"Move to Seek");
1483 return XO(
"Move to Scrub");
1490 return XO(
"Drag to Seek. Release to stop seeking.");
1493 return XO(
"Drag to Seek. Release and move to Scrub.");
1496 return XO(
"Move to Scrub. Drag to Seek.");
1522 const auto &selectedRegion = viewInfo.selectedRegion;
1523 const auto &playRegion = viewInfo.playRegion;
1528 playRegion.GetLastActiveStart(), playRegion.GetLastActiveEnd() }
1566 const auto &playRegion = viewInfo.playRegion;
1567 const auto playRegionBounds = std::pair{
1568 playRegion.GetLastActiveStart(), playRegion.GetLastActiveEnd() };
1584 rectO = rectP.Intersect(rectS);
1587 const auto top = rectP.GetTop(),
1588 bottom = rectP.GetBottom();
1590 wxPoint{ 0, top }, wxPoint{ this->GetSize().GetWidth() - 1, bottom } };
1592 if (!rectO.IsEmpty()) {
1593 rectR = { wxPoint{ rectO.GetRight() + 1, top }, rectL.GetBottomRight() };
1594 rectL = { rectL.GetTopLeft(), wxPoint{ rectO.GetLeft() - 1, bottom } };
1612 dc.DestroyClippingRegion();
1618 mOuter = GetClientRect();
1669 auto bottom = &inner;
1677 top = &scrubZone, topHeight = scrubHeight;
1679 auto qpHeight = scrubZone.height - scrubHeight;
1680 bottom = &scrubZone, topHeight = qpHeight;
1686 top->height = topHeight;
1687 bottom->height -= topHeight;
1688 bottom->y += topHeight;
1733 int pixelPos =
Time2Pos(markerTime);
1737 return mousePosX >= boundLeft && mousePosX < boundRight;
1740#ifdef QUICK_PLAY_HANDLE
1741auto AdornedRulerPanel::QPHandle::Click(
1744 auto result = CommonRulerHandle::Click(event, pProject);
1746 if (mClicked == Button::Left) {
1751 if(scrubber.HasMark()) {
1759 const auto &playRegion = viewInfo.playRegion;
1760 mParent->mOldPlayRegion = playRegion;
1765 mParent->HandleQPClick( event.event, mX );
1766 mParent->HandleQPDrag( event.event, mX );
1786 if (isWithinStart || isWithinEnd) {
1810auto AdornedRulerPanel::QPHandle::Drag(
1813 auto result = CommonRulerHandle::Drag(event, pProject);
1815 if (mClicked == Button::Left) {
1817 mX =
event.event.m_x;
1818 mParent->UpdateQuickPlayPos( mX );
1819 mParent->HandleQPDrag( event.event, mX );
1828 bool isWithinClick =
1835 auto &playRegion = viewInfo.playRegion;
1841 if (isWithinStart || isWithinEnd) {
1868 if (isWithinStart) {
1888 if (isWithinClick) {
1913 mParent->SetNumGuides(1);
1922#ifdef QUICK_PLAY_HANDLE
1923auto AdornedRulerPanel::QPHandle::Preview(
1927 mParent->SetNumGuides(1);
1930 if (mParent && mParent->mTimelineToolTip) {
1931 if (!mParent->mQuickPlayEnabled)
1932 tooltip =
XO(
"Quick-Play disabled");
1934 tooltip =
XO(
"Quick-Play enabled");
1940 const bool scrubbing = scrubber.HasMark();
1948 static wxCursor cursorHand{ wxCURSOR_HAND };
1949 static wxCursor cursorSizeWE{ wxCURSOR_SIZEWE };
1951 bool showArrows =
false;
1954 (mClicked == Button::Left)
1955 || mParent->IsWithinMarker(
1956 state.state.m_x, mParent->mOldPlayRegion.GetStart())
1957 || mParent->IsWithinMarker(
1958 state.state.m_x, mParent->mOldPlayRegion.GetEnd());
1962 showArrows ? &cursorSizeWE : &cursorHand,
1976 auto saveMe = mParent->mQPCell->mHolder.lock();
1980 if (mClicked == Button::Left) {
1982 mParent->HandleQPRelease( event.event );
1985 const auto &playRegion = viewInfo.playRegion;
1986 mParent->mOldPlayRegion = playRegion;
1996 auto &playRegion = viewInfo.playRegion;
2001 const auto &selectedRegion = viewInfo.selectedRegion;
2002 const double sel0 = selectedRegion.t0();
2003 const double sel1 = selectedRegion.t1();
2007 if (evt.ShiftDown() && playRegion.Empty()) {
2011 if (((sel1 < t0) || (sel0 > t1)) &&
2012 ((playRegion.GetStart() < t0) || (playRegion.GetStart() > t1))) {
2017 else if (playRegion.GetStart() >= t1) {
2023 playRegion.GetEnd() - playRegion.GetStart() > 0.0 &&
2024 playRegion.GetEnd() < t0
2033 auto cleanup =
finally( [&] {
2036 SetPlayRegion(mOldPlayRegion.GetStart(), mOldPlayRegion.GetEnd());
2037 SelectUtilities::ActivatePlayRegion(*mProject);
2039 mOldPlayRegion.SetActive( false );
2048 auto result = CommonRulerHandle::Cancel(pProject);
2050 if (mClicked == Button::Left) {
2053 mParent->mMouseEventState = mesNone;
2054 mParent->SetPlayRegion(
2055 mParent->mOldPlayRegion.GetStart(), mParent->mOldPlayRegion.GetEnd());
2056 if (mParent->mOldPlayRegion.Active()) {
2060 mParent->mOldPlayRegion.SetActive(
false );
2070 bool newDefault,
bool cutPreview,
const double *pStartTime)
2075 const auto &playRegion = viewInfo.playRegion;
2076 const auto &selectedRegion = viewInfo.selectedRegion;
2077 const double sel0 = selectedRegion.t0();
2078 const double sel1 = selectedRegion.t1();
2081 bool startPlaying =
true;
2084 bool loopEnabled =
true;
2085 auto oldStart = std::max(0.0, playRegion.GetStart());
2086 double start = oldStart,
end = 0;
2088 if (playRegion.Empty()) {
2090 if (oldStart > sel0 && oldStart < sel1) {
2101 end = std::max(start, playRegion.GetEnd());
2104 loopEnabled = ((
end - start) > 0.001)? true :
false;
2106 newDefault = (loopEnabled && newDefault);
2113 options.pStartTime.emplace(*pStartTime);
2116 options.envelope =
nullptr;
2126 projectAudioManager.Stop();
2143void AdornedRulerPanel::OnToggleScrubRulerFromMenu(wxCommandEvent&)
2146 scrubber.OnToggleScrubRuler(*
mProject);
2153 const auto oldSize = GetSize();
2155 if (
size != oldSize ) {
2158 PostSizeEventToParent();
2167 auto pCellularPanel =
2169 if ( !pCellularPanel ) {
2173 pCellularPanel->DrawOverlays(
false );
2179 auto common = [
this](
2196 pinButton->PushDown();
2198 pinButton->SetAlternateIdx(
2199 (gAudioIO->IsCapturing() ? 2 : 0) + (state ? 0 : 1));
2202 const auto label =
XO(
"Timeline Options");
2203 common(*pinButton,
wxT(
"PinnedHead"),
label);
2226 auto width = viewInfo.GetTracksUsableWidth();
2227 mousePosX = std::max(mousePosX, viewInfo.GetLeftOffset());
2228 mousePosX =
std::min(mousePosX, viewInfo.GetLeftOffset() + width - 1);
2229 const auto time =
Pos2Time(mousePosX);
2243 const auto &playRegion = viewInfo.playRegion;
2248 _(
"Minutes and Seconds"));
2254 _(
"Beats and Measures"));
2258 rulerMenu.AppendSeparator();
2262 pDrag->Enable(playRegion.Active());
2264 rulerMenu.AppendCheckItem(
OnAutoScrollID,
_(
"Update display while playing"))->
2270 item->Check(playRegion.Active());
2281 _(
"Set Loop To Selection"));
2284 rulerMenu.AppendSeparator();
2297 PushEventHandler(&scrubber);
2298 auto cleanup =
finally([
this]{ PopEventHandler(); });
2301 scrubber.PopulatePopupMenu(rulerMenu);
2311 const auto &playRegion = viewInfo.playRegion;
2312 auto &selectedRegion = viewInfo.selectedRegion;
2313 selectedRegion.setT0(playRegion.GetStart(),
false);
2314 selectedRegion.setT1(playRegion.GetEnd(),
true);
2328 auto results = snapManager.Snap(
nullptr,
mQuickPlayPos[index],
false);
2348 int id =
event.GetId();
2373void AdornedRulerPanel::OnTimelineToolTips(wxCommandEvent&)
2385 gPrefs->Write(
wxT(
"/GUI/AutoScroll"),
false);
2387 gPrefs->Write(
wxT(
"/GUI/AutoScroll"),
true);
2416 position = *pPosition;
2419 auto rect = GetRect();
2427 position = { rect.GetLeft() + 38, rect.GetHeight()/2 + 1 };
2446 return clrTrackInfo;
2451 return clrTrackPanelText;
2461 return isActive ? clrRulerBackground : clrClipAffordanceInactiveBrush;
2479 dc->DrawRectangle(
mInner );
2486 ScrubRect.Inflate( 1,0 );
2487 dc->DrawRectangle(ScrubRect);
2499 dc->SetPen( *wxBLACK_PEN );
2509 const double hiddenMin =
Pos2Time(0,
true);
2534 const auto &playRegion = viewInfo.playRegion;
2535 const auto t0 = playRegion.GetLastActiveStart(),
2536 t1 = playRegion.GetLastActiveEnd();
2543 const auto &selectedRegion = viewInfo.selectedRegion;
2544 const auto t0 = selectedRegion.t0(), t1 = selectedRegion.t1();
2550 int p0 = -1, p1 = -1;
2559 const int left = p0, top =
mInner.y, right = p1, bottom =
mInner.GetBottom();
2560 return { wxPoint{left, top}, wxPoint{right, bottom} };
2564 wxDC * dc,
const wxRect &rectP,
const wxRect &rectL,
const wxRect &rectR)
2567 const auto &playRegion = viewInfo.playRegion;
2568 if (playRegion.IsLastActiveRegionClear())
2578 dc->DrawRectangle( rectP.Intersect(rectL) );
2579 dc->DrawRectangle( rectP.Intersect(rectR) );
2587 dc->SetPen( { edgeColour } );
2588 dc->SetBrush( { edgeColour } );
2590 constexpr int side = 7;
2591 constexpr int sideLessOne = side - 1;
2594 const auto left = rect.GetLeft(),
2595 right = rect.GetRight(),
2596 bottom = rect.GetBottom(),
2597 top = rect.GetTop();
2600 {left, bottom - sideLessOne},
2601 {left - sideLessOne, bottom},
2605 dc->DrawPolygon( 4, points );
2612 {right + sideLessOne, bottom},
2613 {right, bottom - sideLessOne},
2615 dc->DrawPolygon( 4, points );
2626 dc->SetPen( *wxTRANSPARENT_PEN );
2627 dc->DrawRectangle( rect );
2631 wxDC * dc,
const wxRect &rectS,
const wxRect &rectL,
const wxRect &rectR)
2635 dc->SetPen( *wxTRANSPARENT_PEN );
2636 dc->DrawRectangle( rectS.Intersect(rectL) );
2637 dc->DrawRectangle( rectS.Intersect(rectR) );
2656 wxDC * dc, wxCoord xx,
int width,
bool scrub,
bool seek)
2664 const int TriangleWidth = width * 3 / 8;
2669 : (
mInner.GetBottom() + 1) - 1 - height;
2673 tri[ 1 ].y = yy + height;
2674 tri[ 2 ].x = xx - TriangleWidth;
2675 tri[ 2 ].y = yy + height / 2;
2676 dc->DrawPolygon( 3, tri );
2678 tri[ 0 ].x -= TriangleWidth;
2679 tri[ 1 ].x -= TriangleWidth;
2680 tri[ 2 ].x -= TriangleWidth;
2681 dc->DrawPolygon( 3, tri );
2684 tri[ 2 ].x = xx + TriangleWidth;
2685 dc->DrawPolygon( 3, tri );
2688 tri[ 0 ].x += TriangleWidth;
2689 tri[ 1 ].x += TriangleWidth;
2690 tri[ 2 ].x += TriangleWidth;
2691 dc->DrawPolygon( 3, tri );
2695 const int IndicatorHalfWidth = width / 2;
2700 : (
mInner.GetBottom() + 1) - 1 - height;
2704 tri[ 1 ].y = yy + height;
2705 tri[ 2 ].x = xx - IndicatorHalfWidth;
2706 tri[ 2 ].y = yy + height / 2;
2707 dc->DrawPolygon( 3, tri );
2709 tri[ 2 ].x = xx + IndicatorHalfWidth;
2710 dc->DrawPolygon( 3, tri );
2715 double playRegionStart,
double playRegionEnd)
2724 auto &playRegion = viewInfo.playRegion;
2725 playRegion.SetTimes( playRegionStart, playRegionEnd );
2735 auto &playRegion = viewInfo.playRegion;
2736 playRegion.SetTimes( -1, -1 );
2749 s_AcceptsFocus =
true;
2757 for (
size_t ii =
mNumGuides; ii < nn; ++ii) {
2808 return scrubber.ShowsBar();
2815 return std::make_shared< MainGroup >( *
this );
2854 std::make_shared<TrackPanelGuidelineOverlay>(
mProject );
2855 auto pCellularPanel =
2857 if ( !pCellularPanel ) {
2861 pCellularPanel->AddOverlay(
mOverlay );
2877 if (scrubber.HasMark())
2878 scrubber.SetScrollScrubbing(value);
2897 Command(
wxT(
"PinnedHead"),
XXO(
"Pinned Play/Record &Head (on/off)"),
EVT_MENU(OnSetPlayRegionToSelectionID, AdornedRulerPanel::OnSetPlayRegionToSelection) EVT_COMMAND(OnTogglePinnedStateID
ColorId TimelineLimitsColor()
decltype(clrTrackInfo) ColorId
ColorId TimelineLoopRegionColor(bool isActive)
static wxColour AlphaBlend(ColorId fg, ColorId bg, double alpha)
static auto handOpenCursor
ColorId TimelineBackgroundColor()
@ OnSetPlayRegionToSelectionID
int IndicatorWidthForHeight(int height)
ColorId TimelineTextColor()
wxEVT_COMMAND_BUTTON_CLICKED
int IndicatorHeightForWidth(int width)
#define SELECT_TOLERANCE_PIXEL
constexpr double SelectionOpacity
IntSetting UpperTimeSignature
The upper time signature of the Beats & Measures ruler.
IntSetting LowerTimeSignature
The lower time signature of the Beats & Measures ruler.
DoubleSetting BeatsPerMinute
The tempo used for drawing the Beats & Measures ruler.
constexpr CommandFlag AlwaysEnabledFlag
XXO("&Cut/Copy/Paste Toolbar")
EVT_COMMAND(wxID_ANY, EVT_FREQUENCYTEXTCTRL_UPDATED, LabelDialog::OnFreqUpdate) LabelDialog
AUDACITY_DLL_API wxWindow & GetProjectPanel(AudacityProject &project)
Get the main sub-window of the project frame that displays track data.
AUDACITY_DLL_API AttachedWindows & GetAttachedWindows(AudacityProject &project)
accessors for certain important windows associated with each project
std::vector< SnapPoint > SnapPointArray
declares abstract base class Track, TrackList, and iterators over TrackList
std::unique_ptr< wxCursor > MakeCursor(int WXUNUSED(CursorId), const char *const pXpm[36], int HotX, int HotY)
TranslatableString Verbatim(wxString str)
Require calls to the one-argument constructor to go through this distinct global function name.
std::shared_ptr< Subclass > AssignUIHandlePtr(std::weak_ptr< Subclass > &holder, const std::shared_ptr< Subclass > &pNew)
BoolSetting ScrollingPreference
const TranslatableString LoopToggleText
static void IndicatorColor(wxDC *dc, bool bIsNotRecording)
static void Line(wxDC &dc, wxCoord x1, wxCoord y1, wxCoord x2, wxCoord y2)
static void SnapGuidePen(wxDC *dc)
static void Light(wxDC *dc, bool selected, bool highlight=false)
static void BevelTrackInfo(wxDC &dc, bool up, const wxRect &r, bool highlight=false)
static void UseThemeColour(wxDC *dc, int iBrush, int iPen=-1, int alpha=255)
Makes temporary drawing context changes that you back out of, RAII style.
CommonCell(AdornedRulerPanel *parent, MenuChoice menuChoice)
unsigned DoContextMenu(const wxRect &, wxWindow *, const wxPoint *pPosition, AudacityProject *) final
AdornedRulerPanel * mParent
HitTestPreview DefaultPreview(const TrackPanelMouseState &, const AudacityProject *) override
const MenuChoice mMenuChoice
Result Click(const TrackPanelMouseEvent &event, AudacityProject *) override
Result Drag(const TrackPanelMouseEvent &, AudacityProject *) override
double Time(AudacityProject &project) const
bool HandlesRightClick() override
Whether the handle has any special right-button handling.
CommonRulerHandle(AdornedRulerPanel *pParent, wxCoord xx, MenuChoice menuChoice)
Result Release(const TrackPanelMouseEvent &event, AudacityProject *, wxWindow *) override
wxWeakRef< AdornedRulerPanel > mParent
void StartPlay(AudacityProject &project, const wxMouseEvent &event)
Result Cancel(AudacityProject *) override
static UIHandle::Result NeedChangeHighlight(const CommonRulerHandle &oldState, const CommonRulerHandle &newState)
void Enter(bool, AudacityProject *) override
void DoStartAdjust(AudacityProject &project, double) override
MovePlayRegionHandle(AdornedRulerPanel *pParent, wxCoord xx)
void DoAdjust(AudacityProject &project) override
NewPlayRegionHandle(AdornedRulerPanel *pParent, wxCoord xx)
void DoAdjust(AudacityProject &project) override
void DoStartAdjust(AudacityProject &project, double time) override
virtual void DoAdjust(AudacityProject &)=0
virtual void DoStartAdjust(AudacityProject &, double)=0
Result Drag(const TrackPanelMouseEvent &event, AudacityProject *pProject) override
HitTestPreview Preview(const TrackPanelMouseState &state, AudacityProject *pProject) override
std::pair< double, double > SnappedTimes(AudacityProject &project)
Result Cancel(AudacityProject *pProject) override
Result Release(const TrackPanelMouseEvent &event, AudacityProject *pProject, wxWindow *pParent) override
void Unsnap(bool use, AudacityProject *pProject)
SelectedRegion mOldSelectedRegion
double SnappedTime(AudacityProject &project, size_t ii)
bool Escape(AudacityProject *pProject) override
PlayRegionAdjustingHandle(AdornedRulerPanel *pParent, wxCoord xx, MenuChoice menuChoice, wxCursor cursor, size_t numGuides=1)
void SavePlayRegion(AudacityProject &project)
bool HasEscape(AudacityProject *pProject) const override
std::vector< UIHandlePtr > HitTest(const TrackPanelMouseState &state, const AudacityProject *pProject) override
std::weak_ptr< NewPlayRegionHandle > mNewPlayRegionHolder
QPCell(AdornedRulerPanel *parent)
std::weak_ptr< PlayheadHandle > mPlayheadHolder
std::shared_ptr< TrackPanelCell > ContextMenuDelegate() override
std::weak_ptr< ResizePlayRegionHandle > mResizePlayRegionHolder
std::weak_ptr< MovePlayRegionHandle > mMovePlayRegionHolder
ResizePlayRegionHandle(AdornedRulerPanel *pParent, wxCoord xx, bool hitLeft)
void DoStartAdjust(AudacityProject &project, double time) override
void DoAdjust(AudacityProject &project) override
std::shared_ptr< TrackPanelCell > ContextMenuDelegate() override
ScrubbingCell(AdornedRulerPanel *parent)
std::weak_ptr< ScrubbingHandle > mHolder
std::vector< UIHandlePtr > HitTest(const TrackPanelMouseState &state, const AudacityProject *pProject) override
Result Cancel(AudacityProject *pProject) override
ScrubbingHandle(AdornedRulerPanel *pParent, wxCoord xx)
Result Drag(const TrackPanelMouseEvent &event, AudacityProject *pProject) override
HitTestPreview Preview(const TrackPanelMouseState &state, AudacityProject *pProject) override
Result Click(const TrackPanelMouseEvent &event, AudacityProject *pProject) override
Result Release(const TrackPanelMouseEvent &event, AudacityProject *pProject, wxWindow *pParent) override
AdornedRulerPanel * GetRuler() const
TrackPanelGuidelineOverlay & mPartner
std::pair< wxRect, bool > DoGetRectangle(wxSize size) override
void Draw(OverlayPanel &panel, wxDC &dc) override
unsigned SequenceNumber() const override
This number determines an ordering of overlays, so that those with higher numbers overpaint those wit...
ScrubbingRulerOverlay(TrackPanelGuidelineOverlay &partner)
void Draw(OverlayPanel &panel, wxDC &dc) override
friend ScrubbingRulerOverlay
TrackPanelGuidelineOverlay(AudacityProject *project)
std::shared_ptr< ScrubbingRulerOverlay > mPartner
std::pair< wxRect, bool > DoGetRectangle(wxSize size) override
AudacityProject * mProject
unsigned SequenceNumber() const override
This number determines an ordering of overlays, so that those with higher numbers overpaint those wit...
This is an Audacity Specific ruler panel which additionally has border, selection markers,...
void OnSelectionChange(Observer::Message)
void UpdatePrefs() override
TrackPanelCell * GetFocusedCell() override
wxRect PlayRegionRectangle() const
void OnPaint(wxPaintEvent &evt)
double mQuickPlayOffset[MAX_GUIDES]
void OnAudioStartStop(AudioIOEvent)
std::shared_ptr< ScrubbingCell > mScrubbingCell
Observer::Subscription mAudioIOSubscription
void OnTogglePinnedState(wxCommandEvent &event)
void DoSelectionChange(const SelectedRegion &selectedRegion)
void SetPlayRegion(double playRegionStart, double playRegionEnd)
void ShowContextMenu(MenuChoice choice, const wxPoint *pPosition)
PlayRegion mOldPlayRegion
wxRect RegionRectangle(double t0, double t1) const
void SetFocusFromKbd() override
void OnSetPlayRegionToSelection(wxCommandEvent &evt)
void DoDrawOverlap(wxDC *dc, const wxRect &rect)
void OnSize(wxSizeEvent &evt)
void OnTimelineFormatChange(wxCommandEvent &evt)
AudacityProject *const mProject
void DoDrawScrubIndicator(wxDC *dc, wxCoord xx, int width, bool scrub, bool seek)
void GetMaxSize(wxCoord *width, wxCoord *height)
void OnPinnedButton(wxCommandEvent &event)
void RefreshTimelineFormat()
void UpdateStatusMessage(const TranslatableString &) override
void OnClearPlayRegion(wxCommandEvent &evt)
wxRect SelectedRegionRectangle() const
void OnIdle(wxIdleEvent &evt)
void ShowScrubMenu(const wxPoint &pos)
bool IsWithinMarker(int mousePosX, double markerTime)
void DoDrawMarks(wxDC *dc, bool)
std::shared_ptr< TrackPanelGuidelineOverlay > mOverlay
bool mLastPlayRegionActive
void OnTogglePlayRegion(wxCommandEvent &evt)
static TempAllowFocus TemporarilyAllowFocus()
std::unique_ptr< bool, Resetter > TempAllowFocus
bool mPlayRegionDragsSelection
void DoDrawPlayRegion(wxDC *dc, const wxRect &rectP, const wxRect &rectL, const wxRect &rectR)
void OnLeave(wxMouseEvent &evt)
std::pair< double, double > mLastDrawnPlayRegion
void DoDrawSelection(wxDC *dc, const wxRect &rectS, const wxRect &rectL, const wxRect &rectR)
static void DragSelection(AudacityProject &project)
void Refresh(bool eraseBackground=true, const wxRect *rect=(const wxRect *) NULL) override
static bool s_AcceptsFocus
void SetLeftOffset(int offset)
void OnAutoScroll(wxCommandEvent &evt)
void HandleQPClick(wxMouseEvent &event, wxCoord mousePosX)
std::shared_ptr< TrackPanelNode > Root() override
Observer::Subscription mPlayRegionSubscription
void HandleQPRelease(wxMouseEvent &event)
int Time2Pos(double t, bool ignoreFisheye=false) const
void ShowMenu(const wxPoint &pos)
AudacityProject * GetProject() const override
bool ShowingScrubRuler() const
void UpdateButtonStates()
void HandleQPDrag(wxMouseEvent &event, wxCoord mousePosX)
void StartQPPlay(bool newDefault, bool cutPreview, const double *pStartTime=nullptr)
Observer::Subscription mThemeChangeSubscription
MouseEventState mMouseEventState
bool mIsSnapped[MAX_GUIDES]
double mQuickPlayPos[MAX_GUIDES]
void DoDrawBackground(wxDC *dc)
std::shared_ptr< QPCell > mQPCell
void OnSyncSelToQuickPlay(wxCommandEvent &evt)
void UpdateQuickPlayPos(wxCoord &mousePosX)
void DoDrawPlayRegionLimits(wxDC *dc, const wxRect &rect)
static AdornedRulerPanel & Get(AudacityProject &project)
AdornedRulerPanel(AudacityProject *project, wxWindow *parent, wxWindowID id, const wxPoint &pos=wxDefaultPosition, const wxSize &size=wxDefaultSize, ViewInfo *viewinfo=NULL)
static constexpr size_t MAX_GUIDES
void SetNumGuides(size_t nn)
void HandleSnapping(size_t index)
double mLeftDownClickUnsnapped
void DoDrawEdge(wxDC *dc)
void ProcessUIHandleResult(TrackPanelCell *pClickedTrack, TrackPanelCell *pLatestCell, unsigned refreshResult) override
double Pos2Time(int p, bool ignoreFisheye=false) const
@ mesSelectingPlayRegionRange
@ mesDraggingPlayRegionStart
@ mesDraggingPlayRegionEnd
@ mesSelectingPlayRegionClick
SelectedRegion mLastDrawnSelectedRegion
static void Destroy(AudacityProject &project)
void SetFocusedCell() override
void OnThemeChange(struct ThemeChangeMessage)
double mQuickPlayPosUnsnapped[MAX_GUIDES]
The top-level handle to an Audacity project. It serves as a source of events that other objects can b...
static AudioIOBase * Get()
wxDC & GetBackingDCForRepaint()
void OnSize(wxSizeEvent &event)
void DisplayBitmap(wxDC &dc)
void Popup(const BasicUI::WindowPlacement &window, const Point &pos={})
Display the menu at pos, invoke at most one action, then hide it.
Formerly part of TrackPanel, this abstract base class has no special knowledge of Track objects and i...
bool CancelDragging(bool escaping)
void HandleCursorForPresentMouseState(bool doHit=true)
Subclass * Find(const RegisteredFactory &key)
Get a (bare) pointer to an attachment, or null, down-cast it to Subclass *; will not create on demand...
Subclass & Get(const RegisteredFactory &key)
Get reference to an attachment, creating on demand if not present, down-cast it to Subclass.
void Assign(const RegisteredFactory &key, ReplacementPointer &&replacement)
Reassign Site's pointer to ClientData.
CommandContext provides additional information to an 'Apply()' command. It provides the project,...
AudacityProject & project
ComponentInterfaceSymbol pairs a persistent string identifier used internally with an optional,...
virtual bool Flush(bool bCurrentOnly=false) wxOVERRIDE
The widget to the left of a ToolBar that allows it to be dragged around to NEW positions.
void SetAsSpacer(bool bIsSpacer)
void SetData(const ZoomInfo *pZoomInfo=nullptr, int leftOffset=0)
Subscription Subscribe(Callback callback)
Connect a callback to the Publisher; later-connected are called earlier.
void DrawOverlays(bool repaint_all, wxDC *pDC=nullptr)
void AddOverlay(const std::weak_ptr< Overlay > &pOverlay)
void SetStart(double start)
void SetTimes(double start, double end)
static void Broadcast(int id=0)
Call this static function to notify all PrefsListener objects.
bool IsAudioActive() const
static AudioIOStartStreamOptions GetDefaultOptions(AudacityProject &project, bool newDefaults=false)
Invoke the global hook, supplying a default argument.
static ProjectAudioIO & Get(AudacityProject &project)
void Stop(bool stopStream=true)
static ProjectAudioManager & Get(AudacityProject &project)
static ProjectStatus & Get(AudacityProject &project)
void Set(const TranslatableString &msg, StatusBarField field=mainStatusBarField)
static ProjectWindow & Get(AudacityProject &project)
void SetTickColour(const wxColour &colour)
void SetFormat(const RulerFormat *pFormat)
void Draw(wxDC &dc) const
void SetTickLengths(const TickLengths &tLengths)
void SetLabelEdges(bool labelEdges)
void GetMaxSize(wxCoord *width, wxCoord *height)
void SetBounds(int left, int top, int right, int bottom)
void SetRange(double min, double max)
void SetTwoTone(bool twoTone)
static bool ShouldScrubPinned()
static Scrubber & Get(AudacityProject &project)
Defines a selected portion of a project.
bool Read(T *pVar) const
overload of Read returning a boolean that is true if the value was previously defined */
wxColour & Colour(int iIndex)
wxSize ImageSize(int iIndex)
double GetEndTime() const
double GetStartTime() const
static TrackList & Get(AudacityProject &project)
std::pair< Axis, Refinement > Subdivision
std::vector< Child > Refinement
static void SetPinnedHeadPreference(bool value, bool flush=false)
static bool GetPinnedHeadPreference()
static double GetPinnedHeadPositionPreference()
static void SetPinnedHeadPositionPreference(double value, bool flush=false)
Holds a msgid for the translation catalog; may also bind format arguments.
wxString Translation() const
TranslatableString Stripped(unsigned options=MenuCodes) const
non-mutating, constructs another TranslatableString object
Short-lived drawing and event-handling object associated with a TrackPanelCell.
virtual HitTestPreview Preview(const TrackPanelMouseState &state, AudacityProject *pProject)=0
bool bUpdateTrackIndicator
NotifyingSelectedRegion selectedRegion
static int UpdateScrollPrefsID()
static ViewInfo & Get(AudacityProject &project)
double PositionToTime(int64 position, int64 origin=0, bool ignoreFisheye=false) const
int64 TimeToPosition(double time, int64 origin=0, bool ignoreFisheye=false) const
STM: Converts a project time to screen x position.
Result Cancel(AudacityProject *) override
AdornedRulerPanel * mpParent
static UIHandle::Result NeedChangeHighlight(const PlayheadHandle &oldState, const PlayheadHandle &newState)
HitTestPreview Preview(const TrackPanelMouseState &, AudacityProject *) override
PlayheadHandle(AdornedRulerPanel &parent, wxCoord xx)
static std::shared_ptr< PlayheadHandle > HitTest(const AudacityProject *pProject, AdornedRulerPanel &parent, wxCoord xx)
void Enter(bool, AudacityProject *) override
Result Click(const TrackPanelMouseEvent &event, AudacityProject *) override
Result Release(const TrackPanelMouseEvent &event, AudacityProject *pProject, wxWindow *) override
Result Drag(const TrackPanelMouseEvent &event, AudacityProject *pProject) override
void SetLabel(const TranslatableString &label)
void SetFocus(const WindowPlacement &focus)
Set the window that accepts keyboard input.
void CallAfter(Action action)
Schedule an action to be done later, and in the main thread.
bool Begin(const FilePath &dataDir)
void Release(wxWindow *handler)
auto end(const Ptr< Type, BaseDeleter > &p)
Enables range-for.
Namespace containing an enum 'what to do on a refresh?'.
void SetPlayRegionToSelection(AudacityProject &project)
void ActivatePlayRegion(AudacityProject &project)
void InactivatePlayRegion(AudacityProject &project)
void ClearPlayRegion(AudacityProject &project)
void TogglePlayRegion(AudacityProject &project)
CommandManager::Options Options
double GetPlayHeadFraction(const AudacityProject *pProject, wxCoord xx)
void OnTogglePinnedHead(const CommandContext &context)
const TranslatableString ScrubbingMessage(const Scrubber &scrubber, bool clicked)
const TranslatableString StartScrubbingMessage(const Scrubber &)
wxCoord GetPlayHeadX(const AudacityProject *pProject)
const TranslatableString ContinueScrubbingMessage(const Scrubber &scrubber, bool clicked)
AttachedWindows::RegisteredFactory sKey
MainGroup(const AdornedRulerPanel &ruler)
Subdivision Children(const wxRect &) override
const AdornedRulerPanel & mRuler
const AdornedRulerPanel & mRuler
Subgroup(const AdornedRulerPanel &ruler)
Subdivision Children(const wxRect &) override
enum AudioIOEvent::Type type
Options && CheckTest(const CheckFn &fn) &&
Default message type for Publisher.
std::optional< PreferredSystemAppearance > appearance