1
0
mirror of https://github.com/cookiengineer/audacity synced 2025-05-05 14:18:53 +02:00

Merge branch 'master' into scrubbing

This commit is contained in:
Paul Licameli 2016-04-28 06:25:06 -04:00
commit a8d85585cf
9 changed files with 241 additions and 90 deletions

View File

@ -878,7 +878,9 @@ Track *TrackList::Add(std::unique_ptr<TrackKind> &&t)
// Make instantiations for the linker to find
template Track *TrackList::Add<TimeTrack>(std::unique_ptr<TimeTrack> &&);
#if defined(USE_MIDI)
template Track *TrackList::Add<NoteTrack>(std::unique_ptr<NoteTrack> &&);
#endif
template Track *TrackList::Add<WaveTrack>(std::unique_ptr<WaveTrack> &&);
template Track *TrackList::Add<LabelTrack>(std::unique_ptr<LabelTrack> &&);

View File

@ -261,17 +261,6 @@ right and top insets
| |+-Border---- ... ----- ... --------------------- ... ... -Border-+|| |
| | Shadow---- ... ----- ... --------------------- ... ... --Shadow-+| |
*/
enum {
kLeftInset = 4,
kRightInset = kLeftInset,
kTopInset = 4,
kShadowThickness = 1,
kBorderThickness = 1,
kTopMargin = kTopInset + kBorderThickness,
kBottomMargin = kShadowThickness + kBorderThickness,
kLeftMargin = kLeftInset + kBorderThickness,
kRightMargin = kRightInset + kShadowThickness + kBorderThickness,
};
// Is the distance between A and B less than D?
template < class A, class B, class DIST > bool within(A a, B b, DIST d)
@ -8811,9 +8800,6 @@ TrackInfo::~TrackInfo()
delete mPan;
}
static const int kTrackInfoWidth = 100;
static const int kTrackInfoBtnSize = 16; // widely used dimension, usually height
int TrackInfo::GetTrackInfoWidth() const
{
return kTrackInfoWidth;

View File

@ -818,6 +818,24 @@ protected:
DECLARE_EVENT_TABLE()
};
// See big pictorial comment in TrackPanel for explanation of these numbers
enum : int {
kLeftInset = 4,
kRightInset = kLeftInset,
kTopInset = 4,
kShadowThickness = 1,
kBorderThickness = 1,
kTopMargin = kTopInset + kBorderThickness,
kBottomMargin = kShadowThickness + kBorderThickness,
kLeftMargin = kLeftInset + kBorderThickness,
kRightMargin = kRightInset + kShadowThickness + kBorderThickness,
};
enum : int {
kTrackInfoWidth = 100,
kTrackInfoBtnSize = 16 // widely used dimension, usually height
};
#ifdef _MSC_VER
#pragma warning( pop )
#endif

View File

@ -111,7 +111,7 @@ void EditCursorOverlay::Draw
}
// AS: Ah, no, this is where we draw the blinky thing in the ruler.
mProject->GetRulerPanel()->DrawCursor(mCursorTime);
mProject->GetRulerPanel()->Refresh();
// This updates related displays such as numbers on the status bar
mProject->TP_DisplaySelection();

View File

@ -763,9 +763,20 @@ void Scrubber::PopulateMenu(wxMenu &menu)
{
int id = CMD_ID;
auto cm = mProject->GetCommandManager();
const MenuItem *checkedItem =
HasStartedScrubbing()
? &FindMenuItem(mSmoothScrollingScrub, mAlwaysSeeking)
: nullptr;
for (const auto &item : menuItems) {
if (cm->GetEnabled(item.name))
if (cm->GetEnabled(item.name)) {
#ifdef CHECKABLE_SCRUB_MENU_ITEMS
menu.AppendCheckItem(id, item.label);
if(&item == checkedItem)
menu.FindItem(id)->Check();
#else
menu.Append(id, item.label);
#endif
}
++id;
}
}

View File

@ -95,7 +95,7 @@ private:
// I need this because I can't push the scrubber as an event handler
// in two places at once.
struct Forwarder : public wxEvtHandler {
Forwarder(Scrubber &scrubber_) : scrubber{ scrubber_ } {}
Forwarder(Scrubber &scrubber_) : scrubber( scrubber_ ) {}
Scrubber &scrubber;

View File

@ -94,8 +94,6 @@ using std::max;
#define PLAY_REGION_RECT_HEIGHT 3
#define PLAY_REGION_GLOBAL_OFFSET_Y 7
#define kTopInset 4
wxColour Ruler::mTickColour{ 153, 153, 153 };
//
@ -1758,7 +1756,9 @@ enum {
OnSyncQuickPlaySelID,
OnTimelineToolTipID,
OnAutoScrollID,
OnLockPlayRegionID
OnLockPlayRegionID,
OnShowHideScrubbingID,
};
BEGIN_EVENT_TABLE(AdornedRulerPanel, wxPanel)
@ -1766,11 +1766,17 @@ BEGIN_EVENT_TABLE(AdornedRulerPanel, wxPanel)
EVT_SIZE(AdornedRulerPanel::OnSize)
EVT_MOUSE_EVENTS(AdornedRulerPanel::OnMouseEvents)
EVT_MOUSE_CAPTURE_LOST(AdornedRulerPanel::OnCaptureLost)
// Context menu commands
EVT_MENU(OnToggleQuickPlayID, AdornedRulerPanel::OnToggleQuickPlay)
EVT_MENU(OnSyncQuickPlaySelID, AdornedRulerPanel::OnSyncSelToQuickPlay)
EVT_MENU(OnTimelineToolTipID, AdornedRulerPanel::OnTimelineToolTips)
EVT_MENU(OnAutoScrollID, AdornedRulerPanel::OnAutoScroll)
EVT_MENU(OnLockPlayRegionID, AdornedRulerPanel::OnLockPlayRegion)
// Main menu commands
EVT_MENU(OnShowHideScrubbingID, AdornedRulerPanel::OnShowHideScrubbing)
END_EVENT_TABLE()
AdornedRulerPanel::AdornedRulerPanel(AudacityProject* parent,
@ -1793,7 +1799,6 @@ AdornedRulerPanel::AdornedRulerPanel(AudacityProject* parent,
mCursorSizeWE = wxCursor(wxCURSOR_SIZEWE);
mLeftOffset = 0;
mCurTime = -1;
mIndTime = -1;
mIndType = -1;
mQuickPlayInd = false;
@ -1809,17 +1814,7 @@ AdornedRulerPanel::AdornedRulerPanel(AudacityProject* parent,
mOuter = GetClientRect();
mInner = mOuter;
mInner.x += 1; // +1 for left bevel
mInner.y += 1; // +1 for top bevel
mInner.width -= 2; // -2 for left and right bevels
mInner.height -= 3; // -3 for top and bottom bevels and bottom line
mRuler.SetUseZoomInfo(mLeftOffset, mViewInfo);
mRuler.SetBounds(mInner.GetLeft(),
mInner.GetTop(),
mInner.GetRight(),
mInner.GetBottom());
mRuler.SetLabelEdges( false );
mRuler.SetFormat( Ruler::TimeFormat );
@ -1868,6 +1863,22 @@ AdornedRulerPanel::~AdornedRulerPanel()
}
}
namespace {
static const wxChar *scrubEnabledPrefName = wxT("/QuickPlay/ScrubbingEnabled");
bool ReadScrubEnabledPref()
{
bool result {};
gPrefs->Read(scrubEnabledPrefName, &result, true);
return result;
}
void WriteScrubEnabledPref(bool value)
{
gPrefs->Write(scrubEnabledPrefName, value);
}
}
void AdornedRulerPanel::UpdatePrefs()
{
#ifdef EXPERIMENTAL_SCROLLING_LIMITS
@ -1879,6 +1890,11 @@ void AdornedRulerPanel::UpdatePrefs()
}
#endif
#endif
mShowScrubbing = ReadScrubEnabledPref();
// Affected by the last
UpdateRects();
RegenerateTooltips();
}
@ -1936,18 +1952,23 @@ enum : int {
IndicatorSmallWidth = 9,
IndicatorMediumWidth = 13,
IndicatorOffset = 1,
TopMargin = 1,
BottomMargin = 2, // for bottom bevel and bottom line
LeftMargin = 1,
RightMargin = 1,
};
inline int IndicatorHeightForWidth(int width)
{
return ((width / 2) * 3) / 2 + 1;
return ((width / 2) * 3) / 2;
}
inline int IndicatorWidthForHeight(int height)
{
// Not an exact inverse of the above, with rounding, but good enough
return std::max(static_cast<int>(IndicatorSmallWidth),
(((height + 1) * 2) / 3) * 2
(((height) * 2) / 3) * 2
);
}
@ -1956,9 +1977,15 @@ int AdornedRulerPanel::IndicatorBigWidth()
return IndicatorWidthForHeight(IndicatorBigHeight());
}
enum {
ScrubHeight = 14,
RulerHeight = 28
};
int AdornedRulerPanel::IndicatorBigHeight()
{
return this->GetSize().GetHeight() / 2;
return std::max(int(ScrubHeight - TopMargin),
int(IndicatorMediumWidth));
}
void AdornedRulerPanel::OnPaint(wxPaintEvent & WXUNUSED(evt))
@ -2015,18 +2042,41 @@ void AdornedRulerPanel::OnSize(wxSizeEvent & WXUNUSED(evt))
return;
}
UpdateRects();
Refresh();
}
void AdornedRulerPanel::UpdateRects()
{
mInner = mOuter;
mInner.x += 1; // +1 for left bevel
mInner.y += 1; // +1 for top bevel
mInner.width -= 2; // -2 for left and right bevels
mInner.height -= 3; // -3 for top and bottom bevels and bottom line
mInner.x += LeftMargin;
mInner.width -= (LeftMargin + RightMargin);
wxRect *top = &mInner;
if (mShowScrubbing) {
mScrubZone = mInner;
auto scrubHeight = std::min(mScrubZone.height, int(ScrubHeight));
mScrubZone.height = scrubHeight;
mInner.height -= scrubHeight;
mInner.y += scrubHeight;
top = &mScrubZone;
}
top->y += TopMargin;
top->height -= TopMargin;
mInner.height -= BottomMargin;
if (!mShowScrubbing)
mScrubZone = mInner;
mRuler.SetBounds(mInner.GetLeft(),
mInner.GetTop(),
mInner.GetRight(),
mInner.GetBottom());
Refresh();
}
double AdornedRulerPanel::Pos2Time(int p, bool ignoreFisheye)
@ -2065,16 +2115,34 @@ void AdornedRulerPanel::OnMouseEvents(wxMouseEvent &evt)
const bool inScrubZone =
// only if scrubbing is allowed now
mProject->GetScrubber().CanScrub() &&
evt.m_y < IndicatorBigHeight();
mShowScrubbing &&
mScrubZone.Contains(evt.GetPosition());
const bool changeInScrubZone = (inScrubZone != mPrevInScrubZone);
mPrevInScrubZone = inScrubZone;
double t0 = mTracks->GetStartTime();
double t1 = mTracks->GetEndTime();
double sel0 = mProject->GetSel0();
double sel1 = mProject->GetSel1();
wxCoord xx = evt.GetX();
wxCoord mousePosX = xx;
UpdateQuickPlayPos(mousePosX);
// If not looping, restrict selection to end of project
if (!inScrubZone && !evt.ShiftDown()) {
mQuickPlayPos = std::min(t1, mQuickPlayPos);
}
// If position was adjusted right, we are over menu
const bool overMenu = (xx < mousePosX);
auto &scrubber = mProject->GetScrubber();
// Handle status bar messages
UpdateStatusBar (
evt.Leaving()
overMenu || evt.Leaving()
? StatusChoice::Leaving
: evt.Entering() || changeInScrubZone
? inScrubZone
@ -2083,18 +2151,25 @@ void AdornedRulerPanel::OnMouseEvents(wxMouseEvent &evt)
: StatusChoice::NoChange
);
if (overMenu && evt.Button(wxMOUSE_BTN_ANY)) {
if(evt.ButtonDown())
DoMainMenu();
return;
}
double t0 = mTracks->GetStartTime();
double t1 = mTracks->GetEndTime();
double sel0 = mProject->GetSel0();
double sel1 = mProject->GetSel1();
// Handle popup menus
if (evt.RightDown() && !(evt.LeftIsDown())) {
if(inScrubZone)
ShowScrubMenu(evt.GetPosition());
else
ShowMenu(evt.GetPosition());
wxCoord mousePosX = evt.GetX();
UpdateQuickPlayPos(mousePosX);
// dismiss and clear Quick-Play indicator
HideQuickPlayIndicator();
// If not looping, restrict selection to end of project
if (!inScrubZone && !evt.ShiftDown()) {
mQuickPlayPos = std::min(t1, mQuickPlayPos);
if (HasCapture())
ReleaseMouse();
return;
}
if (scrubber.HasStartedScrubbing()) {
@ -2157,20 +2232,7 @@ void AdornedRulerPanel::OnMouseEvents(wxMouseEvent &evt)
return;
}
if (evt.RightDown() && !(evt.LeftIsDown())) {
if(inScrubZone)
ShowScrubMenu(evt.GetPosition());
else
ShowMenu(evt.GetPosition());
// dismiss and clear Quick-Play indicator
HideQuickPlayIndicator();
if (HasCapture())
ReleaseMouse();
return;
}
else if (inScrubZone) {
if (inScrubZone) {
if (evt.LeftDown())
scrubber.MarkScrubStart(evt.m_x, false, false);
UpdateStatusBar(StatusChoice::EnteringScrubZone);
@ -2465,6 +2527,32 @@ void AdornedRulerPanel::UpdateStatusBar(StatusChoice choice)
mProject->TP_DisplayStatusMessage(message);
}
void AdornedRulerPanel::DoMainMenu()
{
wxMenu menu;
menu.AppendCheckItem(OnShowHideScrubbingID, _("Scrub Bar"));
menu.Check(OnShowHideScrubbingID, mShowScrubbing);
// Position the popup similarly to the track control panel menus
wxPoint pos {
kLeftInset + kTrackInfoBtnSize + 1,
GetSize().GetHeight() + 1
};
PopupMenu(&menu, pos);
}
void AdornedRulerPanel::OnShowHideScrubbing(wxCommandEvent&)
{
mShowScrubbing = !mShowScrubbing;
WriteScrubEnabledPref(mShowScrubbing);
gPrefs->Flush();
wxSize size { GetSize().GetWidth(), GetRulerHeight(mShowScrubbing) };
SetSize(size);
SetMinSize(size);
PostSizeEventToParent();
}
void AdornedRulerPanel::OnCaptureLost(wxMouseCaptureLostEvent & WXUNUSED(evt))
{
DrawQuickPlayIndicator(NULL);
@ -2618,7 +2706,7 @@ void AdornedRulerPanel::DoDrawPlayRegion(wxDC * dc)
{
int x1 = Time2Pos(start) + 1;
int x2 = Time2Pos(end);
int y = mInner.height/2;
int y = mInner.y - TopMargin + mInner.height/2;
bool isLocked = mProject->IsPlayRegionLocked();
AColor::PlayRegionColor(dc, isLocked);
@ -2671,9 +2759,16 @@ void AdornedRulerPanel::DoDrawBorder(wxDC * dc)
AColor::MediumTrackInfo( dc, false );
dc->DrawRectangle( mInner );
if (mShowScrubbing) {
// Let's distinguish the scrubbing area by using the same gray as for
// selected track control panel.
AColor::Medium(&mBackDC, true);
mBackDC.DrawRectangle(mScrubZone);
}
wxRect r = mOuter;
r.width -= 1; // -1 for bevel
r.height -= 2; // -2 for bevel and for bottom line
r.width -= RightMargin;
r.height -= BottomMargin;
AColor::BevelTrackInfo( *dc, true, r );
dc->SetPen( *wxBLACK_PEN );
@ -2711,31 +2806,34 @@ void AdornedRulerPanel::DoDrawSelection(wxDC * dc)
wxRect r;
r.x = p0;
r.y = 1;
r.y = mInner.y;
r.width = p1 - p0 - 1;
r.height = mInner.height;
dc->DrawRectangle( r );
}
int AdornedRulerPanel::GetRulerHeight()
{
return GetRulerHeight(ReadScrubEnabledPref());
}
int AdornedRulerPanel::GetRulerHeight(bool showScrubBar)
{
return RulerHeight + (showScrubBar ? ScrubHeight : 0);
}
void AdornedRulerPanel::SetLeftOffset(int offset)
{
mLeftOffset = offset;
mRuler.SetUseZoomInfo(offset, mViewInfo);
}
void AdornedRulerPanel::DrawCursor(double time)
{
mCurTime = time;
Refresh();
}
void AdornedRulerPanel::DoDrawCursor(wxDC * dc)
{
const int x = Time2Pos(mCurTime);
const int x = Time2Pos(mViewInfo->selectedRegion.t0());
// Draw cursor in ruler
dc->DrawLine( x, 1, x, mInner.height );
dc->DrawLine( x, mInner.y, x, mInner.y + mInner.height );
}
//
@ -2779,11 +2877,11 @@ void AdornedRulerPanel::DoDrawIndicator
// Double headed, left-right
tri[ 0 ].x = x - IndicatorOffset;
tri[ 0 ].y = 1;
tri[ 0 ].y = mScrubZone.y;
tri[ 1 ].x = x - IndicatorOffset;
tri[ 1 ].y = height;
tri[ 1 ].y = mScrubZone.y + height;
tri[ 2 ].x = x - IndicatorHalfWidth;
tri[ 2 ].y = height / 2;
tri[ 2 ].y = mScrubZone.y + height / 2;
dc->DrawPolygon( 3, tri );
tri[ 0 ].x = tri[ 1 ].x = x + IndicatorOffset;
tri[ 2 ].x = x + IndicatorHalfWidth;
@ -2794,11 +2892,11 @@ void AdornedRulerPanel::DoDrawIndicator
auto height = IndicatorHeightForWidth(width);
const int IndicatorHalfWidth = width / 2;
tri[ 0 ].x = x - IndicatorHalfWidth;
tri[ 0 ].y = 1;
tri[ 0 ].y = mScrubZone.y;
tri[ 1 ].x = x + IndicatorHalfWidth;
tri[ 1 ].y = 1;
tri[ 1 ].y = mScrubZone.y;
tri[ 2 ].x = x;
tri[ 2 ].y = height;
tri[ 2 ].y = mScrubZone.y + height;
dc->DrawPolygon( 3, tri );
}
}
@ -2816,9 +2914,9 @@ void AdornedRulerPanel::DoEraseIndicator(wxDC *dc, int x)
// Restore the background, but make it a little oversized to make
// it happy OSX.
dc->Blit(x - indsize - 1,
0,
mScrubZone.y - 1,
indsize * 2 + 1 + 2,
height + 2,
mScrubZone.y + height + 2,
&mBackDC,
x - indsize - 1,
0);

View File

@ -251,7 +251,7 @@ class AUDACITY_DLL_API RulerPanel final : public wxPanel {
void DoSetSize(int x, int y,
int width, int height,
int sizeFlags = wxSIZE_AUTO);
int sizeFlags = wxSIZE_AUTO) override;
void OnErase(wxEraseEvent &evt);
void OnPaint(wxPaintEvent &evt);
@ -291,10 +291,11 @@ public:
bool AcceptsFocus() const override { return false; };
public:
static int GetRulerHeight() { return 28; }
static int GetRulerHeight();
static int GetRulerHeight(bool showScrubBar);
void SetLeftOffset(int offset);
void DrawCursor(double time);
void DrawIndicator(double time, bool rec);
void DrawSelection();
void ClearIndicator();
@ -318,6 +319,7 @@ private:
void OnCapture(wxCommandEvent & evt);
void OnPaint(wxPaintEvent &evt);
void OnSize(wxSizeEvent &evt);
void UpdateRects();
void OnMouseEvents(wxMouseEvent &evt);
enum class StatusChoice {
@ -328,6 +330,8 @@ private:
};
void UpdateStatusBar(StatusChoice choice);
void DoMainMenu();
void OnCaptureLost(wxMouseCaptureLostEvent &evt);
void DoDrawBorder(wxDC * dc);
@ -364,12 +368,11 @@ private:
wxMemoryDC mBackDC;
wxRect mOuter;
wxRect mScrubZone;
wxRect mInner;
int mLeftOffset; // Number of pixels before we hit the 'zero position'.
double mCurTime;
int mIndType; // -1 = No indicator, 0 = Record, 1 = Play
double mIndTime;
@ -401,6 +404,11 @@ private:
void OnAutoScroll(wxCommandEvent &evt);
void OnLockPlayRegion(wxCommandEvent &evt);
//
// Main menu
//
void OnShowHideScrubbing(wxCommandEvent &evt);
bool mPlayRegionDragsSelection;
bool mTimelineToolTip;
bool mQuickPlayEnabled;
@ -422,6 +430,7 @@ private:
std::unique_ptr<QuickPlayIndicatorOverlay> mOverlay;
bool mPrevInScrubZone{};
bool mShowScrubbing { true };
DECLARE_EVENT_TABLE()
};

View File

@ -28,6 +28,8 @@ public:
void swap(wxFileNameWrapper &that)
{
if (this != &that) {
#if 1
// Awful hack number 1 makes gcc 5 choke
enum : size_t { Size = sizeof(*this) };
// Do it bitwise.
// std::aligned_storage<Size>::type buffer;
@ -35,6 +37,31 @@ public:
memcpy(&buffer, this, Size);
memcpy(this, &that, Size);
memcpy(&that, &buffer, Size);
#else
// Awful hack number 2 relies on knowing the class layout
struct Contents
{
void swap(Contents &that) {
m_volume.swap(that.m_volume);
m_dirs.swap(that.m_dirs);
m_name.swap(that.m_name);
m_ext.swap(that.m_ext);
std::swap(m_relative, that.m_relative);
std::swap(m_hasExt, that.m_hasExt);
std::swap(m_dontFollowLinks, that.m_dontFollowLinks);
};
wxString m_volume;
wxArrayString m_dirs;
wxString m_name, m_ext;
bool m_relative;
bool m_hasExt;
bool m_dontFollowLinks;
};
reinterpret_cast<Contents*>(this)->swap
(*reinterpret_cast<Contents*>(&that));
#endif
}
}