From 78d7ce8aa71281fdbd61b98d29c654fbcced59a6 Mon Sep 17 00:00:00 2001 From: David Bailes Date: Tue, 7 Jun 2016 09:27:02 +0100 Subject: [PATCH 01/41] Fix toolbar grabbers being in tab traversal In commit 89e33da, the override of AcceptsFocus() was removed from the Grabber class so that ESC could cancel the dragging of a toolbar. However this meant that the toolbar grabbers were included in the tab traversal of the toolbars. The fix is to override AcceptsFocusFromKeyboard, rather than AcceptsFocus(). --- src/widgets/Grabber.h | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/widgets/Grabber.h b/src/widgets/Grabber.h index e3b4d0417..a579e8dba 100644 --- a/src/widgets/Grabber.h +++ b/src/widgets/Grabber.h @@ -106,8 +106,9 @@ class Grabber final : public wxWindow // not a need to dock/float a toolbar from the keyboard. If this // changes, remove this and add the necessary keyboard movement // handling. - // PRL: Commented out so the ESC key can stop dragging. - // bool AcceptsFocus() const {return false;} + // Note that AcceptsFocusFromKeyboard() rather than AcceptsFocus() + // is overridden so that ESC can cancel toolbar drag. + bool AcceptsFocusFromKeyboard() const override {return false;} void PushButton(bool state); From fca62853158c16ea5724808770cdd13ca31338f2 Mon Sep 17 00:00:00 2001 From: Steve Daulton Date: Tue, 7 Jun 2016 11:23:11 +0100 Subject: [PATCH 02/41] Add #include for Windows --- src/effects/BassTreble.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/effects/BassTreble.cpp b/src/effects/BassTreble.cpp index d15034b53..24bdf9ff2 100644 --- a/src/effects/BassTreble.cpp +++ b/src/effects/BassTreble.cpp @@ -18,6 +18,7 @@ #include "BassTreble.h" #include +#include #include #include From f21ad1ce49716f743dfbcea12b811f7ac37ed558 Mon Sep 17 00:00:00 2001 From: Paul Licameli Date: Wed, 8 Jun 2016 18:08:51 -0400 Subject: [PATCH 03/41] Pinned playhead for recording is once again always center, not right --- src/toolbars/ControlToolBar.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/toolbars/ControlToolBar.cpp b/src/toolbars/ControlToolBar.cpp index de8b1330a..720cb5fd6 100644 --- a/src/toolbars/ControlToolBar.cpp +++ b/src/toolbars/ControlToolBar.cpp @@ -1281,6 +1281,9 @@ void ControlToolBar::StartScrolling() if (project) { auto mode = Mode::Centered; +#if 0 + // Enable these lines to pin the playhead right instead of center, + // when recording but not overdubbing. if (gAudioIO->GetNumCaptureChannels() > 0) { // recording @@ -1300,6 +1303,7 @@ void ControlToolBar::StartScrolling() if (!duplex) mode = Mode::Right; } +#endif project->GetPlaybackScroller().Activate(mode); } From a6100700385437dfb0306ac8dbef9c619c25a50b Mon Sep 17 00:00:00 2001 From: Paul Licameli Date: Wed, 8 Jun 2016 18:20:23 -0400 Subject: [PATCH 04/41] May always scroll before zero during transport when head is pinned... ... regardless of preferences, but if the Tracks preference is not checked, don't stay scrolled left of zero after stopping. --- src/Project.cpp | 26 ++++++++++++++++++++++---- src/Project.h | 1 + 2 files changed, 23 insertions(+), 4 deletions(-) diff --git a/src/Project.cpp b/src/Project.cpp index 271078dab..5cc178c1e 100644 --- a/src/Project.cpp +++ b/src/Project.cpp @@ -1594,9 +1594,27 @@ void AudacityProject::OnScrollRightButton(wxScrollEvent & event) } +bool AudacityProject::MayScrollBeyondZero() const +{ + if (mViewInfo.bScrollBeyondZero) + return true; + + if (GetScrubber().HasStartedScrubbing() || + IsAudioActive()) { + if (mPlaybackScroller) { + auto mode = mPlaybackScroller->GetMode(); + if (mode == PlaybackScroller::Mode::Centered || + mode == PlaybackScroller::Mode::Right) + return true; + } + } + + return false; +} + double AudacityProject::ScrollingLowerBoundTime() const { - if (!mViewInfo.bScrollBeyondZero) + if (!MayScrollBeyondZero()) return 0; const double screen = mTrackPanel->GetScreenEndTime() - mViewInfo.h; return std::min(mTracks->GetStartTime(), -screen / 2.0); @@ -1708,7 +1726,7 @@ void AudacityProject::FixScrollbars() // may be scrolled to the midline. // May add even more to the end, so that you can always scroll the starting time to zero. const double lowerBound = ScrollingLowerBoundTime(); - const double additional = mViewInfo.bScrollBeyondZero + const double additional = MayScrollBeyondZero() ? -lowerBound + std::max(halfScreen, screen - LastTime) : screen / 4.0; @@ -2045,7 +2063,7 @@ void AudacityProject::OnScroll(wxScrollEvent & WXUNUSED(event)) } - if (mViewInfo.bScrollBeyondZero) { + if (MayScrollBeyondZero()) { enum { SCROLL_PIXEL_TOLERANCE = 10 }; if (std::abs(mViewInfo.TimeToPosition(0.0, 0 )) < SCROLL_PIXEL_TOLERANCE) { @@ -5418,7 +5436,7 @@ void AudacityProject::PlaybackScroller::OnTimer(wxCommandEvent &event) } viewInfo.h = viewInfo.OffsetTimeByPixels(viewInfo.h, deltaX, true); - if (!viewInfo.bScrollBeyondZero) + if (!mProject->MayScrollBeyondZero()) // Can't scroll too far left viewInfo.h = std::max(0.0, viewInfo.h); trackPanel->Refresh(false); diff --git a/src/Project.h b/src/Project.h index 74cb4e54e..f485f1bd8 100644 --- a/src/Project.h +++ b/src/Project.h @@ -407,6 +407,7 @@ class AUDACITY_DLL_API AudacityProject final : public wxFrame, void SafeDisplayStatusMessage(const wxChar *msg); + bool MayScrollBeyondZero() const; double ScrollingLowerBoundTime() const; // How many pixels are covered by the period from lowermost scrollable time, to the given time: // PRL: Bug1197: we seem to need to compute all in double, to avoid differing results on Mac From df0e4945ded6228b316112c774dbb6bac1fc101d Mon Sep 17 00:00:00 2001 From: Paul Licameli Date: Wed, 8 Jun 2016 18:11:54 -0400 Subject: [PATCH 05/41] Remove scrolling left of zero check mark from Tracks menu... ... Less need now to make it more discoverable, because we override an "off" setting during transport with a pinned play head, thus removing some inconsistency and confusion. --- src/Menus.cpp | 19 ------------------- src/Menus.h | 2 -- 2 files changed, 21 deletions(-) diff --git a/src/Menus.cpp b/src/Menus.cpp index 610d9f1ec..ded0c341a 100644 --- a/src/Menus.cpp +++ b/src/Menus.cpp @@ -934,16 +934,6 @@ void AudacityProject::CreateMenusAndCommands() ////////////////////////////////////////////////////////////////////////// - c->AddSeparator(); - c->AddCheck(wxT("ScrollLeftOfZero"), _("Scroll le&ft of zero"), - FN(OnToggleScrollLeftOfZero), - gPrefs->ReadBool( - TracksPrefs::ScrollingPreferenceKey(), - TracksPrefs::ScrollingPreferenceDefault()), - AudioIONotBusyFlag, AudioIONotBusyFlag); - - ////////////////////////////////////////////////////////////////////////// - c->EndMenu(); // All of this is a bit hacky until we can get more things connected into @@ -2550,15 +2540,6 @@ void AudacityProject::OnSortName() mTrackPanel->Refresh(false); } -void AudacityProject::OnToggleScrollLeftOfZero() -{ - auto key = TracksPrefs::ScrollingPreferenceKey(); - auto value = gPrefs->ReadBool(key, TracksPrefs::ScrollingPreferenceDefault()); - gPrefs->Write(key, !value); - gPrefs->Flush(); - UpdatePrefs(); -} - void AudacityProject::OnSkipStart() { wxCommandEvent evt; diff --git a/src/Menus.h b/src/Menus.h index 0b7e6a43f..2a3741870 100644 --- a/src/Menus.h +++ b/src/Menus.h @@ -179,8 +179,6 @@ double GetTime(const Track *t); void OnSortTime(); void OnSortName(); -void OnToggleScrollLeftOfZero(); - void OnSnapToOff(); void OnSnapToNearest(); void OnSnapToPrior(); From 3cb560c7ab2f0c90cf391e62fba6c4d31647e4ec Mon Sep 17 00:00:00 2001 From: James Crook Date: Fri, 10 Jun 2016 13:42:17 +0100 Subject: [PATCH 06/41] Precompiled headers for Windows release builds too. Faster building of release builds on Windows. This force-includes AudacityHeaders.h too. We didn't used to do this because it could hide include file mistakes which would break the build on Linux. We could build the Windows release version to check that includes hadn't been missed out. Now that we have automated Travis builds on Linux we have a better way to check Linux builds aren't broken, and can have faster Windows building of release. --- win/Projects/Audacity/Audacity.vcxproj | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/win/Projects/Audacity/Audacity.vcxproj b/win/Projects/Audacity/Audacity.vcxproj index d83ee11de..c91597ce4 100755 --- a/win/Projects/Audacity/Audacity.vcxproj +++ b/win/Projects/Audacity/Audacity.vcxproj @@ -60,10 +60,12 @@ true MultiThreadedDLL true - .\$(Configuration)/audacity.pch Level3 Default 4996;%(DisableSpecificWarnings) + AudacityHeaders.h;%(ForcedIncludeFiles) + Use + AudacityHeaders.h NDEBUG;%(PreprocessorDefinitions) @@ -121,6 +123,7 @@ Create + Create From 9e74613a8e593a3ffde8fecd26a1adc351dd8f2a Mon Sep 17 00:00:00 2001 From: Gale Andrews Date: Sat, 11 Jun 2016 17:12:33 +0100 Subject: [PATCH 07/41] Disc > Disk (Bug 1400) Also capitalize "Timer Recording" in the message because it is a unique Audacity entity. --- src/TimerRecordDialog.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/TimerRecordDialog.cpp b/src/TimerRecordDialog.cpp index 68f18c96a..c6a43d683 100644 --- a/src/TimerRecordDialog.cpp +++ b/src/TimerRecordDialog.cpp @@ -441,7 +441,7 @@ void TimerRecordDialog::OnOK(wxCommandEvent& WXUNUSED(event)) // Create the message string wxString sMessage = ""; - sMessage.Printf("You may not have enough free disk space to complete this timer recording, based on your current settings.\n\nDo you wish to continue?\n\nPlanned recording duration: %s\nRecording time remaining on disc: %s", + sMessage.Printf("You may not have enough free disk space to complete this Timer Recording, based on your current settings.\n\nDo you wish to continue?\n\nPlanned recording duration: %s\nRecording time remaining on disk: %s", sPlannedTime, sRemainingTime); From 82cf9b3ab642f7de339efdb023f83f158bb220d7 Mon Sep 17 00:00:00 2001 From: Paul Licameli Date: Sat, 11 Jun 2016 16:29:25 -0400 Subject: [PATCH 08/41] Don't increase width when a toolbar is repeatedly docked and undocked --- src/toolbars/ToolBar.h | 3 +++ src/toolbars/ToolDock.cpp | 11 ++++++++--- src/toolbars/ToolDock.h | 2 +- src/toolbars/ToolManager.cpp | 13 +++++++------ 4 files changed, 19 insertions(+), 10 deletions(-) diff --git a/src/toolbars/ToolBar.h b/src/toolbars/ToolBar.h index 340da44de..df942ce69 100644 --- a/src/toolbars/ToolBar.h +++ b/src/toolbars/ToolBar.h @@ -80,6 +80,9 @@ enum ToolBarCount }; +// How may pixels padding each side of a floating toolbar +enum { ToolBarFloatMargin = 1 }; + class ToolBar /* not final */ : public wxPanel { diff --git a/src/toolbars/ToolDock.cpp b/src/toolbars/ToolDock.cpp index f760bccb3..0fe74c51f 100644 --- a/src/toolbars/ToolDock.cpp +++ b/src/toolbars/ToolDock.cpp @@ -129,14 +129,19 @@ int ToolDock::GetBarCount() // // Handle ToolDock events // -void ToolDock::Dock( ToolBar *bar, int before ) +void ToolDock::Dock( ToolBar *bar, bool deflate, int before ) { // Adopt the toolbar into our family bar->Reparent( this ); mBars[ bar->GetId() ] = bar; - // Reset height - bar->SetSize( bar->GetSize().x, bar->GetDockedSize().y ); + // Reset size + bar->SetSize( + // Undo the expansion that was applied when un-docking + bar->GetSize().x - (deflate ? 2 * ToolBarFloatMargin : 0), + // Don't need to adjust y the same way. + bar->GetDockedSize().y + ); // Park the NEW bar in the correct berth if( before >= 0 && before < (int)mDockedBars.GetCount() ) diff --git a/src/toolbars/ToolDock.h b/src/toolbars/ToolDock.h index f45989c06..3475d66f0 100644 --- a/src/toolbars/ToolDock.h +++ b/src/toolbars/ToolDock.h @@ -60,7 +60,7 @@ class ToolDock final : public wxPanel int Find(ToolBar *bar) const; int GetOrder( ToolBar *bar ); int GetBarCount(); - void Dock( ToolBar *bar, int ndx = -1 ); + void Dock( ToolBar *bar, bool deflate, int ndx = -1 ); void Undock( ToolBar *bar ); int PositionBar( ToolBar *t, wxPoint & pos, wxRect & rect ); diff --git a/src/toolbars/ToolManager.cpp b/src/toolbars/ToolManager.cpp index 12f0acb41..f1729de85 100644 --- a/src/toolbars/ToolManager.cpp +++ b/src/toolbars/ToolManager.cpp @@ -136,7 +136,8 @@ class ToolFrame final : public wxFrame width += sizerW; } - SetSize(width + 2, bar->GetDockedSize().y + 2); + SetSize(width + 2 * ToolBarFloatMargin, + bar->GetDockedSize().y + 2 * ToolBarFloatMargin); // Attach the sizer and resize the window to fit SetSizer(s.release()); @@ -557,7 +558,7 @@ void ToolManager::Reset() if( dock != NULL ) { // when we dock, we reparent, so bar is no longer a child of floater. - dock->Dock( bar ); + dock->Dock( bar, false ); Expose( ndx, expose ); //OK (and good) to DELETE floater, as bar is no longer in it. if( floater ) @@ -783,7 +784,7 @@ void ToolManager::ReadConfig() ToolBar *t = mBars[ ndx ]; // Dock it - d->Dock( t ); + d->Dock( t, false ); // Show or hide it Expose( t->GetId(), show[ t->GetId() ] ); @@ -796,7 +797,7 @@ void ToolManager::ReadConfig() ToolBar *t = mBars[ unordered[ dock ][ ord ] ]; // Dock it - d->Dock( t ); + d->Dock( t, false ); // Show or hide the bar Expose( t->GetId(), show[ t->GetId() ] ); @@ -1017,7 +1018,7 @@ void ToolManager::OnMouse( wxMouseEvent & event ) if( mDragDock && !event.ShiftDown() ) { // Trip over...everyone ashore that's going ashore... - mDragDock->Dock( mDragBar, mDragBefore ); + mDragDock->Dock( mDragBar, true, mDragBefore ); // Done with the floater mDragWindow->Destroy(); @@ -1303,7 +1304,7 @@ void ToolManager::HandleEscapeKey() // Why don't you leave me alone? // Well, I feel so break up // I want to go home. - mPrevDock->Dock( mDragBar, mPrevSlot ); + mPrevDock->Dock( mDragBar, true, mPrevSlot ); // Done with the floater mDragWindow->Destroy(); From 64ad732aee27b7ec59272f048436294c8b912471 Mon Sep 17 00:00:00 2001 From: Paul Licameli Date: Wed, 8 Jun 2016 12:21:40 -0400 Subject: [PATCH 09/41] Removed some unused members, made some members const --- src/toolbars/ToolBar.cpp | 6 +++--- src/toolbars/ToolBar.h | 6 +++--- src/toolbars/ToolDock.cpp | 5 ----- src/toolbars/ToolDock.h | 13 ------------- src/toolbars/ToolManager.h | 2 -- 5 files changed, 6 insertions(+), 26 deletions(-) diff --git a/src/toolbars/ToolBar.cpp b/src/toolbars/ToolBar.cpp index d98a08dcf..433d7c851 100644 --- a/src/toolbars/ToolBar.cpp +++ b/src/toolbars/ToolBar.cpp @@ -359,7 +359,7 @@ void ToolBar::SetLabel(const wxString & label) // // Returns whether the toolbar is resizable or not // -bool ToolBar::IsResizable() +bool ToolBar::IsResizable() const { return mResizable; } @@ -367,7 +367,7 @@ bool ToolBar::IsResizable() // // Returns the dock state of the toolbar // -bool ToolBar::IsDocked() +bool ToolBar::IsDocked() const { return mDock != NULL; } @@ -375,7 +375,7 @@ bool ToolBar::IsDocked() // // Returns the visibility of the toolbar // -bool ToolBar::IsVisible() +bool ToolBar::IsVisible() const { return mVisible; } diff --git a/src/toolbars/ToolBar.h b/src/toolbars/ToolBar.h index df942ce69..1e6d28575 100644 --- a/src/toolbars/ToolBar.h +++ b/src/toolbars/ToolBar.h @@ -113,9 +113,9 @@ class ToolBar /* not final */ : public wxPanel // NEW virtual: virtual bool Expose(bool show = true); - bool IsResizable(); - bool IsVisible(); - bool IsDocked(); + bool IsResizable() const; + bool IsVisible() const; + bool IsDocked() const; bool IsPositioned(){ return mPositioned; }; void SetVisible( bool bVisible ); void SetPositioned(){ mPositioned = true;}; diff --git a/src/toolbars/ToolDock.cpp b/src/toolbars/ToolDock.cpp index 0fe74c51f..6ff329d53 100644 --- a/src/toolbars/ToolDock.cpp +++ b/src/toolbars/ToolDock.cpp @@ -121,11 +121,6 @@ void ToolDock::Undock( ToolBar *bar ) } } -int ToolDock::GetBarCount() -{ - return mDockedBars.GetCount(); -} - // // Handle ToolDock events // diff --git a/src/toolbars/ToolDock.h b/src/toolbars/ToolDock.h index 3475d66f0..cadee0df6 100644 --- a/src/toolbars/ToolDock.h +++ b/src/toolbars/ToolDock.h @@ -59,7 +59,6 @@ class ToolDock final : public wxPanel void Expose( int type, bool show ); int Find(ToolBar *bar) const; int GetOrder( ToolBar *bar ); - int GetBarCount(); void Dock( ToolBar *bar, bool deflate, int ndx = -1 ); void Undock( ToolBar *bar ); int PositionBar( ToolBar *t, wxPoint & pos, wxRect & rect ); @@ -74,18 +73,6 @@ class ToolDock final : public wxPanel private: - void ReadConfig(); - void WriteConfig(); - - int FlowLayout( int cnt, - wxRect boxen[], - wxRect ideal[], - int i, - int x, - int y, - int width, - int height ); - void Updated(); int mTotalToolBarHeight; diff --git a/src/toolbars/ToolManager.h b/src/toolbars/ToolManager.h index 111f8a04f..9c3050c12 100644 --- a/src/toolbars/ToolManager.h +++ b/src/toolbars/ToolManager.h @@ -20,7 +20,6 @@ #include "ToolDock.h" #include "ToolBar.h" -class wxArrayPtrVoid; class wxBitmap; class wxCommandEvent; class wxFrame; @@ -108,7 +107,6 @@ class ToolManager final : public wxEvtHandler bool mTransition; #endif - wxArrayPtrVoid mDockedBars; ToolDock *mTopDock; ToolDock *mBotDock; From 203ddfd1a1d658f2d6bfbd8a89fd573671e4ed7a Mon Sep 17 00:00:00 2001 From: Paul Licameli Date: Sat, 11 Jun 2016 15:24:48 -0400 Subject: [PATCH 10/41] Center toolbar dock indicator triangles on edge of rectangle --- src/toolbars/ToolManager.cpp | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/src/toolbars/ToolManager.cpp b/src/toolbars/ToolManager.cpp index f1729de85..afdaafb69 100644 --- a/src/toolbars/ToolManager.cpp +++ b/src/toolbars/ToolManager.cpp @@ -1088,15 +1088,18 @@ void ToolManager::OnMouse( wxMouseEvent & event ) // Decide which direction the arrow should point if( r.GetTop() >= dr.GetHeight() ) { - p.x = dr.GetLeft() + ( dr.GetWidth() / 2 ); - p.y = dr.GetBottom() - mDown->GetBox().GetHeight(); + const auto &box = mDown->GetBox(); + p.x = dr.GetLeft() + ( dr.GetWidth() / 2 ) + - (box.GetWidth() / 2); + p.y = dr.GetBottom() - box.GetHeight(); mCurrent = mDown; } else { + const auto &box = mLeft->GetBox(); p.x = dr.GetLeft() + r.GetLeft(); - p.y = dr.GetTop() + r.GetTop() + mLeft->GetBox().GetHeight() / 2; - //JKC ( ( r.GetHeight() - mLeft->GetBox().GetHeight() ) / 2 ); + p.y = dr.GetTop() + r.GetTop() + + ( ( r.GetHeight() - mLeft->GetBox().GetHeight() ) / 2 ); mCurrent = mLeft; } From de8d0e9918f94ec9a5b91b6900e9a58018c4d266 Mon Sep 17 00:00:00 2001 From: Paul Licameli Date: Sun, 5 Jun 2016 12:32:43 -0400 Subject: [PATCH 11/41] Define Internat::Parenthesize, for good of right-to-left languages --- src/Internat.cpp | 9 +++++++++ src/Internat.h | 2 ++ 2 files changed, 11 insertions(+) diff --git a/src/Internat.cpp b/src/Internat.cpp index 6a5c5f97a..687373cec 100644 --- a/src/Internat.cpp +++ b/src/Internat.cpp @@ -229,3 +229,12 @@ wxString Internat::StripAccelerators(const wxString &s) } return result; } + +wxString Internat::Parenthesize(const wxString &str) +{ + /* i18n-hint: An opening parenthesis, in some languages a right parenthesis */ + auto open = _("("); + /* i18n-hint: A closing parenthesis, in some languages a left parenthesis */ + auto close = _(")"); + return open + str + close; +} diff --git a/src/Internat.h b/src/Internat.h index 1a0306096..dd8465b81 100644 --- a/src/Internat.h +++ b/src/Internat.h @@ -73,6 +73,8 @@ public: * when they aren't, saving translators effort. */ static wxString StripAccelerators(const wxString& str); + static wxString Parenthesize(const wxString &str); + private: static wxChar mDecimalSeparator; From 8dfaa4dcf8cdcafcca36814893b43f58ec1469e4 Mon Sep 17 00:00:00 2001 From: Paul Licameli Date: Sat, 11 Jun 2016 20:26:25 -0400 Subject: [PATCH 12/41] Implement translation of shortcut key names to Mac special chars --- src/commands/Keyboard.cpp | 20 ++++++++++++++++---- src/commands/Keyboard.h | 2 +- 2 files changed, 17 insertions(+), 5 deletions(-) diff --git a/src/commands/Keyboard.cpp b/src/commands/Keyboard.cpp index 194e2a138..6b052bd0e 100644 --- a/src/commands/Keyboard.cpp +++ b/src/commands/Keyboard.cpp @@ -43,13 +43,25 @@ wxString KeyStringNormalize(const wxString & key) #endif } -wxString KeyStringDisplay(const wxString & key) +wxString KeyStringDisplay(const wxString & key, bool useSspecialChars) { wxString newkey = KeyStringNormalize(key); #if defined(__WXMAC__) - newkey.Replace(wxT("XCtrl+"), wxT("Control+")); - newkey.Replace(wxT("Alt+"), wxT("Option+")); - newkey.Replace(wxT("Ctrl+"), wxT("Command+")); + + if (!useSspecialChars) { + // Compose user-visible keystroke names, all ASCII + newkey.Replace(wxT("XCtrl+"), wxT("Control+")); + newkey.Replace(wxT("Alt+"), wxT("Option+")); + newkey.Replace(wxT("Ctrl+"), wxT("Command+")); + } + else { + // Compuse user-visible keystroke names, with special characters + newkey.Replace(wxT("Shift+"), wxT("\u21e7")); + newkey.Replace(wxT("XCtrl+"), wxT("Control+")); + newkey.Replace(wxT("Alt+"), wxT("\u2325")); + newkey.Replace(wxT("Ctrl+"), wxT("\u2318")); + } + #endif return newkey; diff --git a/src/commands/Keyboard.h b/src/commands/Keyboard.h index 2f3ce7559..4f39e6663 100644 --- a/src/commands/Keyboard.h +++ b/src/commands/Keyboard.h @@ -14,5 +14,5 @@ #include wxString KeyStringNormalize(const wxString & key); -wxString KeyStringDisplay(const wxString & key); +wxString KeyStringDisplay(const wxString & key, bool useSpecialChars = false); wxString KeyEventToKeyString(const wxKeyEvent & keyEvent); From 5f8fad4a48a6ca32078df06da6e0aa0779c817ff Mon Sep 17 00:00:00 2001 From: Paul Licameli Date: Sun, 5 Jun 2016 13:11:01 -0400 Subject: [PATCH 13/41] Transport button tooltips with shortcuts use Mac special chars --- src/toolbars/ControlToolBar.cpp | 62 +++++++++++++++------------------ src/toolbars/ToolBar.cpp | 28 +++++++++++++++ src/toolbars/ToolBar.h | 14 +++++++- 3 files changed, 69 insertions(+), 35 deletions(-) diff --git a/src/toolbars/ControlToolBar.cpp b/src/toolbars/ControlToolBar.cpp index 720cb5fd6..d2b7bfd9d 100644 --- a/src/toolbars/ControlToolBar.cpp +++ b/src/toolbars/ControlToolBar.cpp @@ -200,44 +200,38 @@ void ControlToolBar::Populate() void ControlToolBar::RegenerateToolsTooltips() { #if wxUSE_TOOLTIPS + std::vector commands; for (long iWinID = ID_PLAY_BUTTON; iWinID < BUTTON_COUNT; iWinID++) { - wxWindow* pCtrl = this->FindWindow(iWinID); - wxString strToolTip = pCtrl->GetLabel(); - AudacityProject* pProj = GetActiveProject(); - CommandManager* pCmdMgr = (pProj) ? pProj->GetCommandManager() : NULL; - if (pCmdMgr) + commands.clear(); + auto pCtrl = static_cast(this->FindWindow(iWinID)); + commands.push_back(pCtrl->GetLabel()); + switch (iWinID) { - wxString strKey(wxT(" (")); - switch (iWinID) - { - case ID_PLAY_BUTTON: - strKey += pCmdMgr->GetKeyFromName(wxT("Play")); - strKey += _(") / Loop Play ("); - strKey += pCmdMgr->GetKeyFromName(wxT("PlayLooped")); - break; - case ID_RECORD_BUTTON: - strKey += pCmdMgr->GetKeyFromName(wxT("Record")); - strKey += _(") / Append Record ("); - strKey += pCmdMgr->GetKeyFromName(wxT("RecordAppend")); - break; - case ID_PAUSE_BUTTON: - strKey += pCmdMgr->GetKeyFromName(wxT("Pause")); - break; - case ID_STOP_BUTTON: - strKey += pCmdMgr->GetKeyFromName(wxT("Stop")); - break; - case ID_FF_BUTTON: - strKey += pCmdMgr->GetKeyFromName(wxT("SkipEnd")); - break; - case ID_REW_BUTTON: - strKey += pCmdMgr->GetKeyFromName(wxT("SkipStart")); - break; - } - strKey += wxT(")"); - strToolTip += strKey; + case ID_PLAY_BUTTON: + commands.push_back(wxT("Play")); + commands.push_back(_("Loop Play")); + commands.push_back(wxT("PlayLooped")); + break; + case ID_RECORD_BUTTON: + commands.push_back(wxT("Record")); + commands.push_back(_("Append Record")); + commands.push_back(wxT("RecordAppend")); + break; + case ID_PAUSE_BUTTON: + commands.push_back(wxT("Pause")); + break; + case ID_STOP_BUTTON: + commands.push_back(wxT("Stop")); + break; + case ID_FF_BUTTON: + commands.push_back(wxT("SkipEnd")); + break; + case ID_REW_BUTTON: + commands.push_back(wxT("SkipStart")); + break; } - pCtrl->SetToolTip(strToolTip); + ToolBar::SetButtonToolTip(*pCtrl, commands); } #endif } diff --git a/src/toolbars/ToolBar.cpp b/src/toolbars/ToolBar.cpp index 433d7c851..b949dcfd6 100644 --- a/src/toolbars/ToolBar.cpp +++ b/src/toolbars/ToolBar.cpp @@ -48,6 +48,7 @@ in which buttons can be placed. #include "../ImageManipulation.h" #include "../Project.h" #include "../Theme.h" +#include "../commands/Keyboard.h" #include "../widgets/AButton.h" #include "../widgets/Grabber.h" @@ -761,6 +762,33 @@ void ToolBar::MakeAlternateImages(AButton &button, int idx, button.SetAlternateImages(idx, *up, *hilite, *down, *disable); } +void ToolBar::SetButtonToolTip +(AButton &button, const std::vector &commands, const wxString &separator) +{ + const auto project = GetActiveProject(); + const auto commandManager = project ? project->GetCommandManager() : nullptr; + wxString result; + auto iter = commands.begin(), end = commands.end(); + while (iter != end) { + result += *iter++; + if (iter != end) { + if (!iter->empty()) { + if (commandManager) { + auto keyStr = commandManager->GetKeyFromName(*iter); + if (keyStr.empty()) + keyStr = _("no key"); + result += wxT(" "); + result += Internat::Parenthesize(KeyStringDisplay(keyStr, true)); + } + } + ++iter; + } + if (iter != end) + result += separator; + } + button.SetToolTip(result); +} + // // This changes the state a button (from up to down or vice versa) // diff --git a/src/toolbars/ToolBar.h b/src/toolbars/ToolBar.h index 1e6d28575..2392bc675 100644 --- a/src/toolbars/ToolBar.h +++ b/src/toolbars/ToolBar.h @@ -15,6 +15,7 @@ #include "../Experimental.h" +#include #include #include #include @@ -149,7 +150,18 @@ class ToolBar /* not final */ : public wxPanel teBmps eStandardDown, teBmps eDisabled, wxSize size); - + + static + void SetButtonToolTip + (AButton &button, + // An array, alternating user-visible strings, and + // non-user-visible command names. If a shortcut key is defined + // for the command, then it is appended, parenthesized, after the + // user-visible string. + const std::vector &commands, + // If more than one pair of strings is given, then use this separator. + const wxString &separator = wxT(" / ")); + protected: void SetButton(bool down, AButton *button); From 9d33d1242336c4810953c573f868dd7800626d73 Mon Sep 17 00:00:00 2001 From: Paul Licameli Date: Sun, 5 Jun 2016 13:21:57 -0400 Subject: [PATCH 14/41] Ruler button tooltip can use Mac special chars --- src/widgets/Ruler.cpp | 25 +++++++------------------ 1 file changed, 7 insertions(+), 18 deletions(-) diff --git a/src/widgets/Ruler.cpp b/src/widgets/Ruler.cpp index bed7b01ae..7ffa5e655 100644 --- a/src/widgets/Ruler.cpp +++ b/src/widgets/Ruler.cpp @@ -2060,19 +2060,6 @@ void AdornedRulerPanel::UpdatePrefs() RegenerateTooltips(mPrevZone); } -namespace -{ - wxString ComposeButtonLabel - (AudacityProject &project, const wxString &commandName, const wxString &label) - { - auto pCmdMgr = project.GetCommandManager(); - const auto &keyString = pCmdMgr->GetKeyFromName(commandName); - return keyString.empty() - ? label - : label + wxT(" (") + keyString + wxT(")"); - } -} - void AdornedRulerPanel::ReCreateButtons() { for (auto & button : mButtons) { @@ -2797,10 +2784,12 @@ void AdornedRulerPanel::OnContextMenu(wxContextMenuEvent & WXUNUSED(event)) void AdornedRulerPanel::UpdateButtonStates() { auto common = [this] - (wxWindow *button, const wxString &commandName, const wxString &label){ - const auto &fullLabel = ComposeButtonLabel(*mProject, commandName, label); - button->SetLabel(fullLabel); - button->SetToolTip(fullLabel); + (AButton &button, const wxString &commandName, const wxString &label) { + std::vector commands; + commands.push_back(label); + commands.push_back(commandName); + ToolBar::SetButtonToolTip(button, commands); + button.SetLabel(button.GetToolTipText()); }; { @@ -2813,7 +2802,7 @@ void AdornedRulerPanel::UpdateButtonStates() // (which is, to toggle the state) ? _("Pinned play/record Head") : _("Unpinned play/record Head"); - common(pinButton, wxT("PinnedHead"), label); + common(*pinButton, wxT("PinnedHead"), label); } auto &scrubber = mProject->GetScrubber(); From bb7dba2b678735da60b857fa99e963396d5a875f Mon Sep 17 00:00:00 2001 From: Paul Licameli Date: Sat, 11 Jun 2016 19:46:42 -0400 Subject: [PATCH 15/41] Shortcut keys can appear as intended in Track Control Panel menus... ... Delayed construction of the menus was needed. So far this only affects the four menu items that move tracks up and down. --- src/TrackPanel.cpp | 23 +++++++++++++++++++++-- src/TrackPanel.h | 1 + 2 files changed, 22 insertions(+), 2 deletions(-) diff --git a/src/TrackPanel.cpp b/src/TrackPanel.cpp index 44e00f498..0aad99f64 100644 --- a/src/TrackPanel.cpp +++ b/src/TrackPanel.cpp @@ -491,6 +491,9 @@ TrackPanel::TrackPanel(wxWindow * parent, wxWindowID id, mAdjustLeftSelectionCursor = std::make_unique(wxCURSOR_POINT_LEFT); mAdjustRightSelectionCursor = std::make_unique(wxCURSOR_POINT_RIGHT); + // Menu pointers are set to NULL here. Delay building of menus until after + // the command managter is finished, so that we can look up shortcut + // key strings that need to appear in some of the popup menus. mWaveTrackMenu = NULL; mChannelItemsInsertionPoint = 0; @@ -500,8 +503,6 @@ TrackPanel::TrackPanel(wxWindow * parent, wxWindowID id, mRulerWaveformMenu = mRulerSpectrumMenu = NULL; - BuildMenus(); - mTrackArtist = new TrackArtist(); mTrackArtist->SetInset(1, kTopMargin, kRightMargin, kBottomMargin); @@ -586,6 +587,12 @@ TrackPanel::~TrackPanel() delete mInitialTrackSelection; } +void TrackPanel::BuildMenusIfNeeded(void) +{ + if (!mRateMenu) + BuildMenus(); +} + void TrackPanel::BuildMenus(void) { // Get rid of existing menus @@ -676,6 +683,8 @@ void TrackPanel::BuildCommonDropMenuItems(wxMenu * menu) { menu->Append(OnSetNameID, _("&Name...")); menu->AppendSeparator(); + // It is not correct to use KeyStringDisplay here -- wxWidgets will apply + // its equivalent to the key names passed to menu functions. menu->Append(OnMoveUpID, _("Move Track &Up") + wxT("\t") + (GetProject()->GetCommandManager()->GetKeyFromName(wxT("TrackMoveUp")))); menu->Append(OnMoveDownID, _("Move Track &Down") + wxT("\t") + @@ -708,6 +717,8 @@ void TrackPanel::DeleteMenus(void) { // Note that the submenus (mRateMenu, ...) // are deleted by their parent + mRateMenu = mFormatMenu = nullptr; + if (mWaveTrackMenu) { delete mWaveTrackMenu; mWaveTrackMenu = NULL; @@ -7480,6 +7491,8 @@ void TrackPanel::ScrollIntoView(int x) void TrackPanel::OnTrackMenu(Track *t) { + BuildMenusIfNeeded(); + if(!t) { t = GetFocusedTrack(); if(!t) return; @@ -8083,6 +8096,8 @@ void TrackPanel::SetRate(Track * pTrack, double rate) /// track menu. void TrackPanel::OnFormatChange(wxCommandEvent & event) { + BuildMenusIfNeeded(); + int id = event.GetId(); wxASSERT(id >= On16BitID && id <= OnFloatID); wxASSERT(mPopupMenuTarget @@ -8174,6 +8189,8 @@ static int gRates[nRates] = { 8000, 11025, 16000, 22050, 44100, 48000, 88200, 96 /// submenu of the track menu, except for "Other" (/see OnRateOther). void TrackPanel::OnRateChange(wxCommandEvent & event) { + BuildMenusIfNeeded(); + int id = event.GetId(); wxASSERT(id >= OnRate8ID && id <= OnRate384ID); wxASSERT(mPopupMenuTarget @@ -8199,6 +8216,8 @@ int TrackPanel::IdOfRate( int rate ) void TrackPanel::OnRateOther(wxCommandEvent &event) { + BuildMenusIfNeeded(); + wxASSERT(mPopupMenuTarget && mPopupMenuTarget->GetKind() == Track::Wave); diff --git a/src/TrackPanel.h b/src/TrackPanel.h index 49f5dd355..51e8d0a28 100644 --- a/src/TrackPanel.h +++ b/src/TrackPanel.h @@ -147,6 +147,7 @@ class AUDACITY_DLL_API TrackPanel final : public OverlayPanel { virtual ~ TrackPanel(); + virtual void BuildMenusIfNeeded(void); virtual void BuildMenus(void); virtual void DeleteMenus(void); From 16933363fe321c0265ae8f5cd14497315bf24eea Mon Sep 17 00:00:00 2001 From: Paul Licameli Date: Sun, 5 Jun 2016 19:21:26 -0400 Subject: [PATCH 16/41] Update ruler button status messages if changed by keystroke and... ... pointer is in it --- src/widgets/AButton.cpp | 30 ++++++++++++++++++------------ src/widgets/AButton.h | 5 +++++ src/widgets/Ruler.cpp | 2 ++ 3 files changed, 25 insertions(+), 12 deletions(-) diff --git a/src/widgets/AButton.cpp b/src/widgets/AButton.cpp index 83667a5d9..a5110932d 100644 --- a/src/widgets/AButton.cpp +++ b/src/widgets/AButton.cpp @@ -426,18 +426,8 @@ void AButton::OnMouseEvent(wxMouseEvent & event) if (newState != prevState) { Refresh(false); - if (mCursorIsInWindow) { - #if wxUSE_TOOLTIPS // Not available in wxX11 - // Display the tooltip in the status bar - wxToolTip * pTip = this->GetToolTip(); - if( pTip ) { - wxString tipText = pTip->GetTip(); - if (!mEnabled) - tipText += _(" (disabled)"); - GetActiveProject()->TP_DisplayStatusMessage(tipText); - } - #endif - } + if (mCursorIsInWindow) + UpdateStatus(); else { GetActiveProject()->TP_DisplayStatusMessage(wxT("")); } @@ -446,6 +436,22 @@ void AButton::OnMouseEvent(wxMouseEvent & event) event.Skip(); } +void AButton::UpdateStatus() +{ + if (mCursorIsInWindow) { +#if wxUSE_TOOLTIPS // Not available in wxX11 + // Display the tooltip in the status bar + wxToolTip * pTip = this->GetToolTip(); + if( pTip ) { + wxString tipText = pTip->GetTip(); + if (!mEnabled) + tipText += _(" (disabled)"); + GetActiveProject()->TP_DisplayStatusMessage(tipText); + } +#endif + } +} + void AButton::OnCaptureLost(wxMouseCaptureLostEvent & WXUNUSED(event)) { wxMouseEvent e(wxEVT_LEFT_UP); diff --git a/src/widgets/AButton.h b/src/widgets/AButton.h index 6858e7df8..3f1e3eeb4 100644 --- a/src/widgets/AButton.h +++ b/src/widgets/AButton.h @@ -99,6 +99,11 @@ class AButton final : public wxWindow { void OnPaint(wxPaintEvent & event); void OnSize(wxSizeEvent & event); void OnMouseEvent(wxMouseEvent & event); + + // Update the status bar message if the pointer is in the button. + // Else do nothing. + void UpdateStatus(); + void OnCaptureLost(wxMouseCaptureLostEvent & event); void OnKeyDown(wxKeyEvent & event); void OnSetFocus(wxFocusEvent & event); diff --git a/src/widgets/Ruler.cpp b/src/widgets/Ruler.cpp index 7ffa5e655..ed0938c88 100644 --- a/src/widgets/Ruler.cpp +++ b/src/widgets/Ruler.cpp @@ -2790,6 +2790,8 @@ void AdornedRulerPanel::UpdateButtonStates() commands.push_back(commandName); ToolBar::SetButtonToolTip(button, commands); button.SetLabel(button.GetToolTipText()); + + button.UpdateStatus(); }; { From e844b07a4662a41fa88e0a2589ac8b1fc34fbb14 Mon Sep 17 00:00:00 2001 From: Paul Licameli Date: Sat, 11 Jun 2016 23:28:01 -0400 Subject: [PATCH 17/41] All Toolbars define RegenerateTooltips; invoke during project init... ... and UpdatePrefs --- src/Project.cpp | 2 +- src/toolbars/ControlToolBar.cpp | 10 +++++----- src/toolbars/ControlToolBar.h | 2 +- src/toolbars/DeviceToolBar.h | 2 +- src/toolbars/EditToolBar.h | 4 ++-- src/toolbars/MeterToolBar.h | 2 +- src/toolbars/MixerToolBar.cpp | 2 ++ src/toolbars/MixerToolBar.h | 2 ++ src/toolbars/SelectionBar.cpp | 2 ++ src/toolbars/SelectionBar.h | 1 + src/toolbars/SpectralSelectionBar.cpp | 2 ++ src/toolbars/SpectralSelectionBar.h | 2 ++ src/toolbars/ToolBar.h | 1 + src/toolbars/ToolManager.cpp | 8 ++++++++ src/toolbars/ToolManager.h | 1 + src/toolbars/ToolsToolBar.cpp | 6 +++--- src/toolbars/ToolsToolBar.h | 2 +- src/toolbars/TranscriptionToolBar.h | 2 +- 18 files changed, 37 insertions(+), 16 deletions(-) diff --git a/src/Project.cpp b/src/Project.cpp index 5cc178c1e..b87c47050 100644 --- a/src/Project.cpp +++ b/src/Project.cpp @@ -545,7 +545,7 @@ AudacityProject *CreateNewAudacityProject() // Okay, GetActiveProject() is ready. Now we can get its CommandManager, // and add the shortcut keys to the tooltips. - p->GetControlToolBar()->RegenerateToolsTooltips(); + p->GetToolManager()->RegenerateTooltips(); ModuleManager::Get().Dispatch(ProjectInitialized); diff --git a/src/toolbars/ControlToolBar.cpp b/src/toolbars/ControlToolBar.cpp index d2b7bfd9d..4ead8e117 100644 --- a/src/toolbars/ControlToolBar.cpp +++ b/src/toolbars/ControlToolBar.cpp @@ -188,7 +188,7 @@ void ControlToolBar::Populate() mRecord->FollowModifierKeys(); #if wxUSE_TOOLTIPS - RegenerateToolsTooltips(); + RegenerateTooltips(); wxToolTip::Enable(true); wxToolTip::SetDelay(1000); #endif @@ -197,7 +197,7 @@ void ControlToolBar::Populate() ArrangeButtons(); } -void ControlToolBar::RegenerateToolsTooltips() +void ControlToolBar::RegenerateTooltips() { #if wxUSE_TOOLTIPS std::vector commands; @@ -256,14 +256,14 @@ void ControlToolBar::UpdatePrefs() if( updated ) { - ReCreateButtons(); // side effect: calls RegenerateToolsTooltips() + ReCreateButtons(); // side effect: calls RegenerateTooltips() Updated(); } else // The other reason to regenerate tooltips is if keyboard shortcuts for // transport buttons changed, but that's too much work to check for, so just // always do it. (Much cheaper than calling ReCreateButtons() in all cases. - RegenerateToolsTooltips(); + RegenerateTooltips(); // Set label to pull in language change @@ -377,7 +377,7 @@ void ControlToolBar::ReCreateButtons() EnableDisableButtons(); - RegenerateToolsTooltips(); + RegenerateTooltips(); } void ControlToolBar::Repaint( wxDC *dc ) diff --git a/src/toolbars/ControlToolBar.h b/src/toolbars/ControlToolBar.h index 29fc21893..9171dfcef 100644 --- a/src/toolbars/ControlToolBar.h +++ b/src/toolbars/ControlToolBar.h @@ -101,7 +101,7 @@ class ControlToolBar final : public ToolBar { void EnableDisableButtons() override; void ReCreateButtons() override; - void RegenerateToolsTooltips(); + void RegenerateTooltips() override; int WidthForStatusBar(wxStatusBar* const); void UpdateStatusBar(AudacityProject *pProject); diff --git a/src/toolbars/DeviceToolBar.h b/src/toolbars/DeviceToolBar.h index 261d3ccb6..c1a114119 100644 --- a/src/toolbars/DeviceToolBar.h +++ b/src/toolbars/DeviceToolBar.h @@ -63,7 +63,7 @@ class DeviceToolBar final : public ToolBar { void SetDevices(const DeviceSourceMap *in, const DeviceSourceMap *out); void RepositionCombos(); void SetNames(); - void RegenerateTooltips(); + void RegenerateTooltips() override; void ShowComboDialog(wxChoice *combo, const wxString &title); diff --git a/src/toolbars/EditToolBar.h b/src/toolbars/EditToolBar.h index 7f3496b51..aedf2a1bd 100644 --- a/src/toolbars/EditToolBar.h +++ b/src/toolbars/EditToolBar.h @@ -83,7 +83,7 @@ class EditToolBar final : public ToolBar { void MakeButtons(); - void RegenerateTooltips(); + void RegenerateTooltips() override; AButton *mButtons[ETBNumButtons]; @@ -136,7 +136,7 @@ public: void EnableDisableButtons(); void UpdatePrefs(); - void RegenerateTooltips(); + void RegenerateTooltips() override; private: diff --git a/src/toolbars/MeterToolBar.h b/src/toolbars/MeterToolBar.h index 6b5dac7f5..e6af911aa 100644 --- a/src/toolbars/MeterToolBar.h +++ b/src/toolbars/MeterToolBar.h @@ -53,7 +53,7 @@ class MeterToolBar final : public ToolBar { wxSize GetDockedSize(); private: - void RegenerateTooltips(); + void RegenerateTooltips() override; AudacityProject *mProject; int mWhichMeters; diff --git a/src/toolbars/MixerToolBar.cpp b/src/toolbars/MixerToolBar.cpp index 172d1c6af..43a5c0644 100644 --- a/src/toolbars/MixerToolBar.cpp +++ b/src/toolbars/MixerToolBar.cpp @@ -196,6 +196,8 @@ void MixerToolBar::UpdatePrefs() // Set label to pull in language change SetLabel(_("Mixer")); + RegenerateTooltips(); + // Give base class a chance ToolBar::UpdatePrefs(); } diff --git a/src/toolbars/MixerToolBar.h b/src/toolbars/MixerToolBar.h index cc94c67df..3ef6ed155 100644 --- a/src/toolbars/MixerToolBar.h +++ b/src/toolbars/MixerToolBar.h @@ -49,6 +49,8 @@ class MixerToolBar final : public ToolBar { void AdjustOutputGain(int adj); void AdjustInputGain(int adj); + void RegenerateTooltips() override {}; + protected: float mInputSliderVolume; float mOutputSliderVolume; diff --git a/src/toolbars/SelectionBar.cpp b/src/toolbars/SelectionBar.cpp index ce665490c..0eaa66344 100644 --- a/src/toolbars/SelectionBar.cpp +++ b/src/toolbars/SelectionBar.cpp @@ -296,6 +296,8 @@ void SelectionBar::UpdatePrefs() // Set label to pull in language change SetLabel(_("Selection")); + RegenerateTooltips(); + // Give base class a chance ToolBar::UpdatePrefs(); } diff --git a/src/toolbars/SelectionBar.h b/src/toolbars/SelectionBar.h index fe3f19e2e..4756e282d 100644 --- a/src/toolbars/SelectionBar.h +++ b/src/toolbars/SelectionBar.h @@ -49,6 +49,7 @@ class SelectionBar final : public ToolBar { void SetSelectionFormat(const wxString & format); void SetRate(double rate); void SetListener(SelectionBarListener *l); + void RegenerateTooltips() override {}; private: diff --git a/src/toolbars/SpectralSelectionBar.cpp b/src/toolbars/SpectralSelectionBar.cpp index 7dc674892..bef455779 100644 --- a/src/toolbars/SpectralSelectionBar.cpp +++ b/src/toolbars/SpectralSelectionBar.cpp @@ -209,6 +209,8 @@ void SpectralSelectionBar::UpdatePrefs() // Set label to pull in language change SetLabel(_("Spectral Selection")); + RegenerateTooltips(); + // Give base class a chance ToolBar::UpdatePrefs(); } diff --git a/src/toolbars/SpectralSelectionBar.h b/src/toolbars/SpectralSelectionBar.h index 75581f98f..54ad0bc32 100644 --- a/src/toolbars/SpectralSelectionBar.h +++ b/src/toolbars/SpectralSelectionBar.h @@ -46,6 +46,8 @@ public: void SetBandwidthSelectionFormatName(const wxString & formatName); void SetListener(SpectralSelectionBarListener *l); + void RegenerateTooltips() override {}; + private: void ValuesToControls(); diff --git a/src/toolbars/ToolBar.h b/src/toolbars/ToolBar.h index 2392bc675..8b7f0b3a9 100644 --- a/src/toolbars/ToolBar.h +++ b/src/toolbars/ToolBar.h @@ -99,6 +99,7 @@ class ToolBar /* not final */ : public wxPanel virtual void EnableDisableButtons() = 0; virtual void ReCreateButtons(); virtual void UpdatePrefs(); + virtual void RegenerateTooltips() = 0; int GetType(); wxString GetTitle(); diff --git a/src/toolbars/ToolManager.cpp b/src/toolbars/ToolManager.cpp index afdaafb69..4366b21d6 100644 --- a/src/toolbars/ToolManager.cpp +++ b/src/toolbars/ToolManager.cpp @@ -598,6 +598,14 @@ void ToolManager::Reset() Updated(); } +void ToolManager::RegenerateTooltips() +{ + for (auto bar : mBars) { + if (bar) + bar->RegenerateTooltips(); + } +} + // // Read the toolbar states // diff --git a/src/toolbars/ToolManager.h b/src/toolbars/ToolManager.h index 9c3050c12..40174fedd 100644 --- a/src/toolbars/ToolManager.h +++ b/src/toolbars/ToolManager.h @@ -65,6 +65,7 @@ class ToolManager final : public wxEvtHandler ToolDock *GetBotDock(); void Reset(); + void RegenerateTooltips(); private: diff --git a/src/toolbars/ToolsToolBar.cpp b/src/toolbars/ToolsToolBar.cpp index 20f0f3d03..bd74bb5e4 100644 --- a/src/toolbars/ToolsToolBar.cpp +++ b/src/toolbars/ToolsToolBar.cpp @@ -111,7 +111,7 @@ ToolsToolBar::~ToolsToolBar() { } -void ToolsToolBar::RegenerateToolsTooltips() +void ToolsToolBar::RegenerateTooltips() { // JKC: @@ -150,7 +150,7 @@ void ToolsToolBar::RegenerateToolsTooltips() void ToolsToolBar::UpdatePrefs() { - RegenerateToolsTooltips(); + RegenerateTooltips(); } AButton * ToolsToolBar::MakeTool( teBmps eTool, @@ -183,7 +183,7 @@ void ToolsToolBar::Populate() mTool[mCurrentTool]->PushDown(); - RegenerateToolsTooltips(); + RegenerateTooltips(); } /// Gets the currently active tool diff --git a/src/toolbars/ToolsToolBar.h b/src/toolbars/ToolsToolBar.h index 4cc7937e9..0e76696c9 100644 --- a/src/toolbars/ToolsToolBar.h +++ b/src/toolbars/ToolsToolBar.h @@ -70,7 +70,7 @@ class ToolsToolBar final : public ToolBar { private: - void RegenerateToolsTooltips(); + void RegenerateTooltips() override; wxImage *MakeToolImage(wxImage *tool, wxImage *mask, int style); AButton *MakeTool(teBmps eTool, int id, const wxChar *label); diff --git a/src/toolbars/TranscriptionToolBar.h b/src/toolbars/TranscriptionToolBar.h index 734b37cce..28b7810d9 100644 --- a/src/toolbars/TranscriptionToolBar.h +++ b/src/toolbars/TranscriptionToolBar.h @@ -131,7 +131,7 @@ class TranscriptionToolBar final : public ToolBar { int id, unsigned altIdx); void GetSamples(WaveTrack *t, sampleCount *s0, sampleCount *slen); void SetButton(bool newstate, AButton *button); - void RegenerateTooltips(); + void RegenerateTooltips() override; AButton *mButtons[TTBNumButtons]; wxImage *upImage; From 1f72f8db18b7c3a9a5046f7ed8bd4ba2022f3624 Mon Sep 17 00:00:00 2001 From: Paul Licameli Date: Sat, 11 Jun 2016 23:30:12 -0400 Subject: [PATCH 18/41] Tools toolbar buttons mention shortcuts in status messages --- src/toolbars/ToolsToolBar.cpp | 28 ++++++++++++++++++++++------ 1 file changed, 22 insertions(+), 6 deletions(-) diff --git a/src/toolbars/ToolsToolBar.cpp b/src/toolbars/ToolsToolBar.cpp index bd74bb5e4..e75842e16 100644 --- a/src/toolbars/ToolsToolBar.cpp +++ b/src/toolbars/ToolsToolBar.cpp @@ -136,12 +136,28 @@ void ToolsToolBar::RegenerateTooltips() // wxSafeYield(); //Deal with some queued up messages... #if wxUSE_TOOLTIPS - mTool[selectTool]->SetToolTip(_("Selection Tool")); - mTool[envelopeTool]->SetToolTip(_("Envelope Tool")); - mTool[slideTool]->SetToolTip(_("Time Shift Tool")); - mTool[zoomTool]->SetToolTip(_("Zoom Tool")); - mTool[drawTool]->SetToolTip(_("Draw Tool")); - mTool[multiTool]->SetToolTip(_("Multi-Tool Mode")); + + static const struct Entry { + int tool; + wxString commandName; + wxString untranslatedLabel; + } table[] = { + { selectTool, wxT("SelectTool"), XO("Selection Tool") }, + { envelopeTool, wxT("EnvelopeTool"), XO("Envelope Tool") }, + { slideTool, wxT("TimeShiftTool"), XO("Time Shift Tool") }, + { zoomTool, wxT("ZoomTool"), XO("Zoom Tool") }, + { drawTool, wxT("DrawTool"), XO("Draw Tool") }, + { multiTool, wxT("MultiTool"), XO("Multi Tool") }, + }; + + std::vector commands; + for (const auto &entry : table) { + commands.clear(); + commands.push_back(wxGetTranslation(entry.untranslatedLabel)); + commands.push_back(entry.commandName); + ToolBar::SetButtonToolTip(*mTool[entry.tool], commands); + } + #endif // wxSafeYield(); From c1a22816f89a4475d2555a33f5478c793d0bf377 Mon Sep 17 00:00:00 2001 From: Paul Licameli Date: Sat, 11 Jun 2016 23:38:29 -0400 Subject: [PATCH 19/41] Tooltip for Transcription play button mentions the shortcut... ... but only for the version without shift or ctrl modifier key. Should it mention those others too? It might get too long. --- src/toolbars/TranscriptionToolBar.cpp | 20 +++++++++++++++++++- 1 file changed, 19 insertions(+), 1 deletion(-) diff --git a/src/toolbars/TranscriptionToolBar.cpp b/src/toolbars/TranscriptionToolBar.cpp index c4f22af04..334a26de2 100644 --- a/src/toolbars/TranscriptionToolBar.cpp +++ b/src/toolbars/TranscriptionToolBar.cpp @@ -298,7 +298,25 @@ void TranscriptionToolBar::UpdatePrefs() void TranscriptionToolBar::RegenerateTooltips() { - mButtons[TTB_PlaySpeed]->SetToolTip(_("Play-at-speed")); + // We could also mention the shift- and ctrl-modified versions in the + // tool tip... but it would get long + + static const struct Entry { + int tool; + wxString commandName; + wxString untranslatedLabel; + } table[] = { + { TTB_PlaySpeed, wxT("PlayAtSpeed"), XO("Play-at-speed") }, + }; + + std::vector commands; + for (const auto &entry : table) { + commands.clear(); + commands.push_back(wxGetTranslation(entry.untranslatedLabel)); + commands.push_back(entry.commandName); + ToolBar::SetButtonToolTip(*mButtons[entry.tool], commands); + } + #ifdef EXPERIMENTAL_VOICE_DETECTION mButtons[TTB_StartOn]->SetToolTip(TRANSLATABLE("Left-to-On")); From 0e0df1f2ff2052ba70d7fbd4a70aa30b701d84d6 Mon Sep 17 00:00:00 2001 From: Paul Licameli Date: Sat, 11 Jun 2016 23:59:05 -0400 Subject: [PATCH 20/41] Edit toolbar tooltips mention shortcut keys --- src/toolbars/EditToolBar.cpp | 46 ++++++++++++++++++++++++------------ 1 file changed, 31 insertions(+), 15 deletions(-) diff --git a/src/toolbars/EditToolBar.cpp b/src/toolbars/EditToolBar.cpp index 2dca40e34..009fc6b71 100644 --- a/src/toolbars/EditToolBar.cpp +++ b/src/toolbars/EditToolBar.cpp @@ -198,24 +198,40 @@ void EditToolBar::UpdatePrefs() void EditToolBar::RegenerateTooltips() { #if wxUSE_TOOLTIPS - mButtons[ETBCutID]->SetToolTip(_("Cut")); - mButtons[ETBCopyID]->SetToolTip(_("Copy")); - mButtons[ETBPasteID]->SetToolTip(_("Paste")); - mButtons[ETBTrimID]->SetToolTip(_("Trim Audio")); - mButtons[ETBSilenceID]->SetToolTip(_("Silence Audio")); - mButtons[ETBUndoID]->SetToolTip(_("Undo")); - mButtons[ETBRedoID]->SetToolTip(_("Redo")); - #ifdef EXPERIMENTAL_SYNC_LOCK - mButtons[ETBSyncLockID]->SetToolTip(_("Sync-Lock Tracks")); - #endif - mButtons[ETBZoomInID]->SetToolTip(_("Zoom In")); - mButtons[ETBZoomOutID]->SetToolTip(_("Zoom Out")); - mButtons[ETBZoomSelID]->SetToolTip(_("Fit Selection")); - mButtons[ETBZoomFitID]->SetToolTip(_("Fit Project")); + static const struct Entry { + int tool; + wxString commandName; + wxString untranslatedLabel; + } table[] = { + { ETBCutID, wxT("Cut"), XO("Cut") }, + { ETBCopyID, wxT("Copy"), XO("Copy") }, + { ETBPasteID, wxT("Paste"), XO("Paste") }, + { ETBTrimID, wxT("Trim"), XO("Trim Audio") }, + { ETBSilenceID, wxT("Silence"), XO("Silence Audio") }, + { ETBUndoID, wxT("Undo"), XO("Undo") }, + { ETBRedoID, wxT("Redo"), XO("Redo") }, + +#ifdef EXPERIMENTAL_SYNC_LOCK + { ETBSyncLockID, wxT("SyncLock"), XO("Sync-Lock Tracks") }, +#endif + + { ETBZoomInID, wxT("ZoomIn"), XO("Zoom In") }, + { ETBZoomOutID, wxT("ZoomOut"), XO("Zoom Out") }, + { ETBZoomSelID, wxT("ZoomSel"), XO("Fit Selection") }, + { ETBZoomFitID, wxT("FitInWindow"), XO("Fit Project") }, #if defined(EXPERIMENTAL_EFFECTS_RACK) - mButtons[ETBEffectsID]->SetToolTip(_("Open Effects Rack")); + { ETBEffectsID, wxT(""), XO("Open Effects Rack") }, #endif + }; + + std::vector commands; + for (const auto &entry : table) { + commands.clear(); + commands.push_back(wxGetTranslation(entry.untranslatedLabel)); + commands.push_back(entry.commandName); + ToolBar::SetButtonToolTip(*mButtons[entry.tool], commands); + } #endif } From 1b1b0ba5e7566e6e4823b47f0112cf92714fada5 Mon Sep 17 00:00:00 2001 From: Paul Licameli Date: Sun, 12 Jun 2016 08:24:27 -0400 Subject: [PATCH 21/41] Remove forward declaration of nonexistent type --- src/Project.h | 1 - 1 file changed, 1 deletion(-) diff --git a/src/Project.h b/src/Project.h index f485f1bd8..29d9173e6 100644 --- a/src/Project.h +++ b/src/Project.h @@ -78,7 +78,6 @@ class Scrubber; class ScrubbingToolBar; class SelectionBar; class SpectralSelectionBar; -class Toolbar; class ToolManager; class ToolsToolBar; class TranscriptionToolBar; From 036c13149b39f8a8fe6e6778a0fbcb4a8833644f Mon Sep 17 00:00:00 2001 From: Paul Licameli Date: Wed, 8 Jun 2016 12:22:35 -0400 Subject: [PATCH 22/41] The two toolbar positioning functions are simpler and more similar --- src/toolbars/ToolDock.cpp | 345 +++++++++++++++++--------------------- src/toolbars/ToolDock.h | 2 +- 2 files changed, 153 insertions(+), 194 deletions(-) diff --git a/src/toolbars/ToolDock.cpp b/src/toolbars/ToolDock.cpp index 6ff329d53..19dfeb3d4 100644 --- a/src/toolbars/ToolDock.cpp +++ b/src/toolbars/ToolDock.cpp @@ -161,129 +161,10 @@ void ToolDock::Dock( ToolBar *bar, bool deflate, int before ) // void ToolDock::LayoutToolBars() { - wxRect stack[ ToolBarCount + 1 ]; - wxPoint cpos, lpos; ToolBar *lt = NULL; - int ndx, stkcnt = 0; - int width, height; - - // Get size of our parent since we haven't been sized yet - GetParent()->GetClientSize( &width, &height ); - width -= toolbarGap; - height -= toolbarGap; - - // Get the number of docked toolbars and take a quick exit - // if we don't have any - int cnt = mDockedBars.GetCount(); - if( cnt == 0 ) - { - SetMinSize( wxSize( width, toolbarGap ) ); - return; - } - - // Set initial stack entry to maximum size - stack[ 0 ].SetX( toolbarGap ); - stack[ 0 ].SetY( toolbarGap ); - stack[ 0 ].SetWidth( width ); - stack[ 0 ].SetHeight( height ); - - // Process all docked and visible toolbars - for( ndx = 0; ndx < cnt; ndx++ ) - { - // Cache toolbar pointer - ToolBar *ct = (ToolBar *)mDockedBars[ ndx ]; - - // Get and cache the toolbar sizes - wxSize sz = ct->GetSize(); - int tw = sz.GetWidth() + toolbarGap; - int th = sz.GetHeight() + toolbarGap; - - // Will this one fit in remaining horizontal space? - if( ( tw > stack[ stkcnt ].GetWidth() ) || - ( th > stack[ stkcnt ].GetHeight() ) ) - { - // Destack entries until one is found in which this bar - // will fit or until we run out of stacked entries - while( stkcnt > 0 ) - { - stkcnt--; - - // Get out if it will fit - if( ( tw <= stack[ stkcnt ].GetWidth() ) && - ( th <= stack[ stkcnt ].GetHeight() ) ) - { - break; - } - } - } - - // The current stack entry position is where the bar - // will be placed. - cpos = stack[ stkcnt ].GetPosition(); - - // We'll be using at least a portion of this stack entry, so - // adjust the location and size. It is possible that these - // will become zero if this entry and the toolbar have the - // same height. This is what we want as it will be destacked - // in the next iteration. - stack[ stkcnt ].SetY( stack[ stkcnt ].GetY() + th ); - stack[ stkcnt ].SetHeight( stack[ stkcnt ].GetHeight() - th ); - - // Calc the next possible horizontal location. - int x = cpos.x + tw; - - // Add a NEW stack entry - stkcnt++; - stack[ stkcnt ].SetX( x ); - stack[ stkcnt ].SetY( cpos.y ); - stack[ stkcnt ].SetWidth( width - x ); - stack[ stkcnt ].SetHeight( th ); - - // Position the previous toolbar - if( ndx > 0 ) - { - // Keep the tab order in order - ct->MoveAfterInTabOrder( lt ); - - // Place the last toolbar - lt->SetPosition( wxPoint( lpos.x, lpos.y ) ); - } - - // Place the final toolbar - if( ndx == cnt - 1 ) - { - ct->SetPosition( wxPoint( cpos.x, cpos.y ) ); - } - - // Remember for next iteration - lt = ct; - lpos = cpos; - } - - // Set the final size of the dock window - SetMinSize( wxSize( -1, stack[ 0 ].GetY() ) ); - - // Clean things up - Refresh( false ); -} - -// -// Determine the location and bar before which a NEW bar would be placed -// -// 'rect' will be the rectangle for the dock marker. -int ToolDock::PositionBar( ToolBar *t, wxPoint & pos, wxRect & rect ) -{ - struct - { - wxRect rect; - wxSize min; - } tinfo[ ToolBarCount + 1 ]; wxRect stack[ ToolBarCount + 1 ]; - wxPoint cpos, lpos; - int ct, lt = 0; - int ndx, stkcnt = 0; - int tindx = -1; + int stkcnt = 0; int cnt = mDockedBars.GetCount(); int width, height; @@ -300,58 +181,13 @@ int ToolDock::PositionBar( ToolBar *t, wxPoint & pos, wxRect & rect ) stack[ 0 ].SetHeight( height ); // Process all docked and visible toolbars - // - // Careful...slightly different from above in that we expect to - // process one more bar than is currently docked (<= in for) - for (ndx = 0, ct = 0; ndx <= cnt; ndx++, ct++) + for( int ndx = 0; ndx < cnt; ndx++ ) { - // If last entry, then it is the - if (ndx == cnt) - { - // ...so check to see if the NEW bar has been placed yet - if (tindx == -1) - { - // Add the NEW bars' dimensions to the mix - tinfo[ct].rect = t->GetRect(); - tinfo[ct].min = t->GetDockedSize(); - tindx = ct; - } - } - else - { - // Cache toolbar pointer - ToolBar *b = (ToolBar *)mDockedBars[ndx]; - - // Remember current bars' dimensions - tinfo[ct].rect = b->GetRect(); - tinfo[ct].min = b->GetSize(); - - // Maybe insert the NEW bar if it hasn't already been done - // and is in the right place. - if (tindx == -1) - { - wxRect r; - - // Get bar rect and make gap part of it - r.SetPosition(b->GetParent()->ClientToScreen(b->GetPosition())); - r.SetSize(b->IsResizable() ? b->GetSize() : b->GetSize()); - r.width += toolbarGap; - r.height += toolbarGap; - - // Does the location fall within this bar? - if (r.Contains(pos) || pos.y <= r.y) - { - // Add the NEW bars' dimensions to the mix - tinfo[ct].rect = t->GetRect(); - tinfo[ct].min = t->GetDockedSize(); - tindx = ct; - ndx--; - } - } - } + // Cache toolbar pointer + ToolBar *ct = (ToolBar *)mDockedBars[ ndx ]; // Get and cache the toolbar sizes - wxSize sz = tinfo[ct].min; + wxSize sz = ct->GetSize(); int tw = sz.GetWidth() + toolbarGap; int th = sz.GetHeight() + toolbarGap; @@ -375,7 +211,152 @@ int ToolDock::PositionBar( ToolBar *t, wxPoint & pos, wxRect & rect ) // The current stack entry position is where the bar // will be placed. - cpos = stack[stkcnt].GetPosition(); + const auto cpos = stack[ stkcnt ].GetPosition(); + + // Position the previous toolbar + if( ndx > 0 ) + { + // Keep the tab order in order + ct->MoveAfterInTabOrder( lt ); + } + + // Place the toolbar + ct->SetPosition( wxPoint( cpos.x, cpos.y ) ); + + // Remember for next iteration + lt = ct; + + // We'll be using at least a portion of this stack entry, so + // adjust the location and size. It is possible that these + // will become zero if this entry and the toolbar have the + // same height. This is what we want as it will be destacked + // in the next iteration. + stack[ stkcnt ].SetY( stack[ stkcnt ].GetY() + th ); + stack[ stkcnt ].SetHeight( stack[ stkcnt ].GetHeight() - th ); + + // Calc the next possible horizontal location. + int x = cpos.x + tw; + + // Add a NEW stack entry + stkcnt++; + stack[ stkcnt ].SetX( x ); + stack[ stkcnt ].SetY( cpos.y ); + stack[ stkcnt ].SetWidth( width - x ); + stack[ stkcnt ].SetHeight( th ); + } + + // Set the final size of the dock window + SetMinSize( wxSize( stack[ 0 ].width, stack[ 0 ].GetY() ) ); + + // Clean things up + Refresh( false ); +} + +// +// Determine the location and bar before which a NEW bar would be placed +// +// 'rect' will be the rectangle for the dock marker. +int ToolDock::PositionBar( ToolBar *t, const wxPoint & pos, wxRect & rect ) +{ + int tindx = -1; + + wxRect stack[ ToolBarCount + 1 ]; + int stkcnt = 0; + int cnt = mDockedBars.GetCount(); + int width, height; + + // Get size of our parent since we haven't been sized yet + GetParent()->GetClientSize( &width, &height ); + width -= toolbarGap; + height -= toolbarGap; + + // Set initial stack entry to maximum size + stack[ 0 ].SetX( toolbarGap ); + stack[ 0 ].SetY( toolbarGap ); + // The stack width and height are the remaining width and height. + stack[ 0 ].SetWidth( width ); + stack[ 0 ].SetHeight( height ); + + // Process all docked and visible toolbars + // + // Careful...slightly different from above in that we expect to + // process one more bar than is currently docked (<= in for) + for ( int ndx = 0; ndx <= cnt; ndx++) + { + wxRect sz; + + // If last entry, then it is the + if (ndx == cnt) + { + // Add the NEW bars' dimensions to the mix + rect = t->GetRect(); + sz = t->GetDockedSize(); + tindx = ndx; + } + else + { + // Cache toolbar pointer + ToolBar *ct = (ToolBar *)mDockedBars[ndx]; + + // Remember current bars' dimensions + sz = ct->GetSize(); + + // Maybe insert the NEW bar if it hasn't already been done + // and is in the right place. + if (tindx == -1) + { + wxRect r; + + // Get bar rect and make gap part of it + r.SetPosition(ct->GetParent()->ClientToScreen(ct->GetPosition())); + r.SetSize(ct->IsResizable() ? ct->GetSize() : ct->GetSize()); + r.width += toolbarGap; + r.height += toolbarGap; + + // Does the location fall within this bar? + if (r.Contains(pos) || pos.y <= r.y) + { + // Add the NEW bars' dimensions to the mix + rect = t->GetRect(); + sz = t->GetDockedSize(); + tindx = ndx; + } + } + } + + // Get and cache the toolbar sizes + int tw = sz.GetWidth() + toolbarGap; + int th = sz.GetHeight() + toolbarGap; + + // This loop reduces stkcnt until it gives a box + // that we fit in. + while (stkcnt > 0) + { + // Get out if it will fit + bool bTooWide = tw > stack[stkcnt].GetWidth(); + // We'd like to be able to add a tall toolbar in at the start of a row, + // even if there isn't enough height for it. + // If so, we'd have to at least change how we calculate 'bTooHigh'. + bool bTooHigh = th > stack[stkcnt].GetHeight(); + //bTooHigh &= stack[stkcnt].GetWidth() < (width - toolbarGap); + //bTooHigh = false; + + if (!bTooWide && !bTooHigh) + break; + stkcnt--; + } + + // The current stack entry position is where the bar + // will be placed. + const auto cpos = stack[stkcnt].GetPosition(); + + // If we've placed it, we're done. + if (tindx != -1) + { + rect.x = cpos.x; + rect.y = cpos.y; + break; + } // We'll be using at least a portion of this stack entry, so // adjust the location and size. It is possible that these @@ -394,31 +375,9 @@ int ToolDock::PositionBar( ToolBar *t, wxPoint & pos, wxRect & rect ) stack[stkcnt].SetY(cpos.y); stack[stkcnt].SetWidth(width - x); stack[stkcnt].SetHeight(th); - - // Position the previous toolbar - if (ndx > 0) - { - // Place the unstretched toolbar - tinfo[lt].rect.x = lpos.x; - tinfo[lt].rect.y = lpos.y; - } - - // Remember for next iteration - lt = ct; - lpos = cpos; - - // If we've placed it, we're done. - if (tindx != -1) - { - tinfo[tindx].rect.x = cpos.x; - tinfo[tindx].rect.y = cpos.y; - break; - } } - // Fill in the final position - rect = tinfo[ tindx ].rect; - + // rect is decided return tindx; } diff --git a/src/toolbars/ToolDock.h b/src/toolbars/ToolDock.h index cadee0df6..c87070f5c 100644 --- a/src/toolbars/ToolDock.h +++ b/src/toolbars/ToolDock.h @@ -61,7 +61,7 @@ class ToolDock final : public wxPanel int GetOrder( ToolBar *bar ); void Dock( ToolBar *bar, bool deflate, int ndx = -1 ); void Undock( ToolBar *bar ); - int PositionBar( ToolBar *t, wxPoint & pos, wxRect & rect ); + int PositionBar( ToolBar *t, const wxPoint & pos, wxRect & rect ); protected: From dd327cd30433720c47d6cff8c03752102e39fcd9 Mon Sep 17 00:00:00 2001 From: Paul Licameli Date: Mon, 6 Jun 2016 12:13:01 -0400 Subject: [PATCH 23/41] More abstract toolbar positioning types, to be generalized later --- src/toolbars/ToolDock.cpp | 98 +++++++++++++++++++----------------- src/toolbars/ToolDock.h | 46 +++++++++++++++-- src/toolbars/ToolManager.cpp | 2 +- src/toolbars/ToolManager.h | 5 +- 4 files changed, 99 insertions(+), 52 deletions(-) diff --git a/src/toolbars/ToolDock.cpp b/src/toolbars/ToolDock.cpp index 19dfeb3d4..d309d6ee2 100644 --- a/src/toolbars/ToolDock.cpp +++ b/src/toolbars/ToolDock.cpp @@ -48,6 +48,32 @@ #include "../widgets/AButton.h" #include "../widgets/Grabber.h" +void ToolBarConfiguration::Insert(ToolBar *bar, Position position) +{ + if (position >= size() || position == UnspecifiedPosition) + push_back(bar); + else + wxArrayPtrVoid::Insert(bar, position); +} + +void ToolBarConfiguration::Remove(const ToolBar *bar) +{ + wxArrayPtrVoid::Remove(const_cast(bar)); +} + +void ToolBarConfiguration::Show(ToolBar *bar) +{ + // Do not assume the bar is absent, though in practice that is always so + if (!Contains(bar)) + Insert(bar); +} + +void ToolBarConfiguration::Hide(ToolBar *bar) +{ + // Future: might hide a bar without eliminating it from the configuration + Remove(bar); +} + IMPLEMENT_CLASS( ToolDock, wxPanel ); //////////////////////////////////////////////////////////// @@ -95,7 +121,7 @@ ToolDock::~ToolDock() // int ToolDock::GetOrder( ToolBar *bar ) { - int order = mDockedBars.Index( bar ); + int order = mConfiguration.Index( bar ); if( order == wxNOT_FOUND ) { @@ -115,16 +141,17 @@ int ToolDock::GetOrder( ToolBar *bar ) // void ToolDock::Undock( ToolBar *bar ) { - if( mDockedBars.Index( bar ) != wxNOT_FOUND ) + if( mConfiguration.Contains( bar ) ) { - mDockedBars.Remove( bar ); + mConfiguration.Remove( bar ); + mBars[ bar->GetId() ] = nullptr; } } // // Handle ToolDock events // -void ToolDock::Dock( ToolBar *bar, bool deflate, int before ) +void ToolDock::Dock( ToolBar *bar, bool deflate, ToolBarConfiguration::Position position ) { // Adopt the toolbar into our family bar->Reparent( this ); @@ -139,14 +166,8 @@ void ToolDock::Dock( ToolBar *bar, bool deflate, int before ) ); // Park the NEW bar in the correct berth - if( before >= 0 && before < (int)mDockedBars.GetCount() ) - { - mDockedBars.Insert( bar, before ); - } - else - { - mDockedBars.Add( bar ); - } + if (!mConfiguration.Contains(bar)) + mConfiguration.Insert( bar, position ); // Inform toolbar of change bar->SetDocked( this, false ); @@ -165,7 +186,7 @@ void ToolDock::LayoutToolBars() wxRect stack[ ToolBarCount + 1 ]; int stkcnt = 0; - int cnt = mDockedBars.GetCount(); + int cnt = mConfiguration.GetCount(); int width, height; // Get size of our parent since we haven't been sized yet @@ -184,7 +205,7 @@ void ToolDock::LayoutToolBars() for( int ndx = 0; ndx < cnt; ndx++ ) { // Cache toolbar pointer - ToolBar *ct = (ToolBar *)mDockedBars[ ndx ]; + ToolBar *ct = (ToolBar *)mConfiguration[ ndx ]; // Get and cache the toolbar sizes wxSize sz = ct->GetSize(); @@ -253,16 +274,17 @@ void ToolDock::LayoutToolBars() } // -// Determine the location and bar before which a NEW bar would be placed +// Determine the position where a NEW bar would be placed // // 'rect' will be the rectangle for the dock marker. -int ToolDock::PositionBar( ToolBar *t, const wxPoint & pos, wxRect & rect ) +ToolBarConfiguration::Position + ToolDock::PositionBar( ToolBar *t, const wxPoint & pos, wxRect & rect ) { - int tindx = -1; + auto tindx = ToolBarConfiguration::UnspecifiedPosition; wxRect stack[ ToolBarCount + 1 ]; int stkcnt = 0; - int cnt = mDockedBars.GetCount(); + int cnt = mConfiguration.GetCount(); int width, height; // Get size of our parent since we haven't been sized yet @@ -296,14 +318,14 @@ int ToolDock::PositionBar( ToolBar *t, const wxPoint & pos, wxRect & rect ) else { // Cache toolbar pointer - ToolBar *ct = (ToolBar *)mDockedBars[ndx]; + ToolBar *ct = (ToolBar *)mConfiguration[ndx]; - // Remember current bars' dimensions + // Remember current bars ' dimensions sz = ct->GetSize(); // Maybe insert the NEW bar if it hasn't already been done // and is in the right place. - if (tindx == -1) + if (tindx == ToolBarConfiguration::UnspecifiedPosition) { wxRect r; @@ -351,7 +373,7 @@ int ToolDock::PositionBar( ToolBar *t, const wxPoint & pos, wxRect & rect ) const auto cpos = stack[stkcnt].GetPosition(); // If we've placed it, we're done. - if (tindx != -1) + if (tindx != ToolBarConfiguration::UnspecifiedPosition) { rect.x = cpos.x; rect.y = cpos.y; @@ -389,20 +411,11 @@ void ToolDock::Expose( int type, bool show ) ToolBar *t = mBars[ type ]; // Maintain the docked array - if( show ) - { - if( mDockedBars.Index( t ) == wxNOT_FOUND ) - { - mDockedBars.Add( t ); - } - } - else - { - if( mDockedBars.Index( t ) != wxNOT_FOUND ) - { - mDockedBars.Remove( t ); - } - } + const auto shown = mConfiguration.Shows( t ); + if( show && !shown ) + mConfiguration.Show( t ); + else if( !show && shown ) + mConfiguration.Hide( t ); // Make it (dis)appear t->Expose( show ); @@ -412,11 +425,6 @@ void ToolDock::Expose( int type, bool show ) Updated(); } -int ToolDock::Find(ToolBar *bar) const -{ - return mDockedBars.Index(bar); -} - // // Queues an EVT_TOOLBAR_UPDATED command event to notify any // interested parties of an updated toolbar or dock layout @@ -441,7 +449,7 @@ void ToolDock::OnGrabber( GrabberEvent & event ) mManager->ProcessEvent( event ); // We no longer have control - mDockedBars.Remove( t ); + mConfiguration.Remove( t ); } } @@ -489,10 +497,10 @@ void ToolDock::OnPaint( wxPaintEvent & WXUNUSED(event) ) AColor::Line(dc, 0, 0, 0, sz.GetHeight() ); // Draw the gap between each bar - int ndx, cnt = mDockedBars.GetCount(); + int ndx, cnt = mConfiguration.GetCount(); for( ndx = 0; ndx < cnt; ndx++ ) { - wxRect r = ( (ToolBar *)mDockedBars[ ndx ] )->GetRect(); + wxRect r = ( (ToolBar *)mConfiguration[ ndx ] )->GetRect(); AColor::Line( dc, r.GetLeft(), @@ -505,7 +513,7 @@ void ToolDock::OnPaint( wxPaintEvent & WXUNUSED(event) ) { // ...and for bars that aren't the last in a row, draw an // horizontal gap line - if( r.y == ( (ToolBar *)mDockedBars[ ndx + 1 ] )->GetRect().y ) + if( r.y == ( (ToolBar *)mConfiguration[ ndx + 1 ] )->GetRect().y ) { AColor::Line(dc, r.GetRight() + 1, diff --git a/src/toolbars/ToolDock.h b/src/toolbars/ToolDock.h index c87070f5c..6ff71a066 100644 --- a/src/toolbars/ToolDock.h +++ b/src/toolbars/ToolDock.h @@ -45,6 +45,37 @@ enum DockCount = 2 }; +class ToolBarConfiguration : public wxArrayPtrVoid +{ +public: + using Position = int; + static const Position UnspecifiedPosition = -1; + + Position Find(const ToolBar *bar) const + { + return Index(const_cast(bar)); + } + + bool Contains(const ToolBar *bar) const + { + return Find(bar) != UnspecifiedPosition; + } + + // Default position inserts at the end + void Insert(ToolBar *bar, + Position position = UnspecifiedPosition); + void Remove(const ToolBar *bar); + + // Future: might allow a state that the configuration remembers + // a hidden bar, but for now, it's equivalent to Contains(): + bool Shows(const ToolBar *bar) const { return Contains(bar); } + + void Show(ToolBar *bar); + void Hide(ToolBar *bar); + +private: +}; + class ToolDock final : public wxPanel { @@ -57,11 +88,16 @@ class ToolDock final : public wxPanel void LayoutToolBars(); void Expose( int type, bool show ); - int Find(ToolBar *bar) const; int GetOrder( ToolBar *bar ); - void Dock( ToolBar *bar, bool deflate, int ndx = -1 ); + void Dock( ToolBar *bar, bool deflate, + ToolBarConfiguration::Position ndx + = ToolBarConfiguration::UnspecifiedPosition); void Undock( ToolBar *bar ); - int PositionBar( ToolBar *t, const wxPoint & pos, wxRect & rect ); + ToolBarConfiguration::Position + PositionBar( ToolBar *t, const wxPoint & pos, wxRect & rect ); + + ToolBarConfiguration &GetConfiguration() + { return mConfiguration; } protected: @@ -80,7 +116,9 @@ class ToolDock final : public wxPanel ToolManager *mManager; - wxArrayPtrVoid mDockedBars; + // Stores adjacency relations that we want to realize in the dock layout + ToolBarConfiguration mConfiguration; + ToolBar *mBars[ ToolBarCount ]; public: diff --git a/src/toolbars/ToolManager.cpp b/src/toolbars/ToolManager.cpp index 4366b21d6..bafb4740a 100644 --- a/src/toolbars/ToolManager.cpp +++ b/src/toolbars/ToolManager.cpp @@ -1253,7 +1253,7 @@ void ToolManager::OnGrabber( GrabberEvent & event ) if (mDragBar->IsDocked()) { mPrevDock = dynamic_cast(mDragBar->GetParent()); wxASSERT(mPrevDock); - mPrevSlot = mPrevDock->Find(mDragBar); + mPrevSlot = mPrevDock->GetConfiguration().Find(mDragBar); } else mPrevPosition = mDragBar->GetParent()->GetPosition(); diff --git a/src/toolbars/ToolManager.h b/src/toolbars/ToolManager.h index 40174fedd..44a843f08 100644 --- a/src/toolbars/ToolManager.h +++ b/src/toolbars/ToolManager.h @@ -91,7 +91,7 @@ class ToolManager final : public wxEvtHandler ToolDock *mDragDock; ToolBar *mDragBar {}; wxPoint mDragOffset; - int mDragBefore; + ToolBarConfiguration::Position mDragBefore {}; wxPoint mLastPos; wxRect mBarPos; @@ -115,7 +115,8 @@ class ToolManager final : public wxEvtHandler wxPoint mPrevPosition {}; ToolDock *mPrevDock {}; - int mPrevSlot {-1}; + ToolBarConfiguration::Position mPrevSlot + { ToolBarConfiguration::UnspecifiedPosition }; public: From b46e263afb6ada8aebc92cf96adf24f9d8745fa5 Mon Sep 17 00:00:00 2001 From: Paul Licameli Date: Wed, 8 Jun 2016 14:08:34 -0400 Subject: [PATCH 24/41] Abstract ToolBarConfiguration further, with an iterator class --- src/toolbars/ToolDock.cpp | 34 ++++++++++++++--------- src/toolbars/ToolDock.h | 57 +++++++++++++++++++++++++++++++++++++++ 2 files changed, 79 insertions(+), 12 deletions(-) diff --git a/src/toolbars/ToolDock.cpp b/src/toolbars/ToolDock.cpp index d309d6ee2..448e9bcca 100644 --- a/src/toolbars/ToolDock.cpp +++ b/src/toolbars/ToolDock.cpp @@ -48,6 +48,14 @@ #include "../widgets/AButton.h" #include "../widgets/Grabber.h" +auto ToolBarConfiguration::FindPlace(const ToolBar *bar) const + -> Iterator +{ + return std::find_if(begin(), end(), + [=](const Place &place){ return place.pBar == bar; } + ); +} + void ToolBarConfiguration::Insert(ToolBar *bar, Position position) { if (position >= size() || position == UnspecifiedPosition) @@ -182,11 +190,10 @@ void ToolDock::Dock( ToolBar *bar, bool deflate, ToolBarConfiguration::Position // void ToolDock::LayoutToolBars() { - ToolBar *lt = NULL; + ToolBar *lt = nullptr; wxRect stack[ ToolBarCount + 1 ]; int stkcnt = 0; - int cnt = mConfiguration.GetCount(); int width, height; // Get size of our parent since we haven't been sized yet @@ -202,10 +209,10 @@ void ToolDock::LayoutToolBars() stack[ 0 ].SetHeight( height ); // Process all docked and visible toolbars - for( int ndx = 0; ndx < cnt; ndx++ ) + for (const auto &place : GetConfiguration()) { // Cache toolbar pointer - ToolBar *ct = (ToolBar *)mConfiguration[ ndx ]; + ToolBar *ct = place.pBar; // Get and cache the toolbar sizes wxSize sz = ct->GetSize(); @@ -235,7 +242,7 @@ void ToolDock::LayoutToolBars() const auto cpos = stack[ stkcnt ].GetPosition(); // Position the previous toolbar - if( ndx > 0 ) + if( lt ) { // Keep the tab order in order ct->MoveAfterInTabOrder( lt ); @@ -284,7 +291,6 @@ ToolBarConfiguration::Position wxRect stack[ ToolBarCount + 1 ]; int stkcnt = 0; - int cnt = mConfiguration.GetCount(); int width, height; // Get size of our parent since we haven't been sized yet @@ -302,23 +308,27 @@ ToolBarConfiguration::Position // Process all docked and visible toolbars // // Careful...slightly different from above in that we expect to - // process one more bar than is currently docked (<= in for) - for ( int ndx = 0; ndx <= cnt; ndx++) + // process one more bar than is currently docked + for ( auto iter = GetConfiguration().begin(), + end = GetConfiguration().end(); + ; // iterate once more at end + ++iter ) { wxRect sz; // If last entry, then it is the - if (ndx == cnt) + if (iter == end) { // Add the NEW bars' dimensions to the mix rect = t->GetRect(); sz = t->GetDockedSize(); - tindx = ndx; + // This will break the loop + tindx = iter->position; } else { // Cache toolbar pointer - ToolBar *ct = (ToolBar *)mConfiguration[ndx]; + ToolBar *ct = iter->pBar; // Remember current bars ' dimensions sz = ct->GetSize(); @@ -341,7 +351,7 @@ ToolBarConfiguration::Position // Add the NEW bars' dimensions to the mix rect = t->GetRect(); sz = t->GetDockedSize(); - tindx = ndx; + tindx = iter->position; } } } diff --git a/src/toolbars/ToolDock.h b/src/toolbars/ToolDock.h index 6ff71a066..0d066a58e 100644 --- a/src/toolbars/ToolDock.h +++ b/src/toolbars/ToolDock.h @@ -51,6 +51,62 @@ public: using Position = int; static const Position UnspecifiedPosition = -1; + struct Place { + ToolBar *pBar {}; + Position position { UnspecifiedPosition }; + }; + + class Iterator + : public std::iterator + { + public: + const Place &operator * () const { return mPlace; } + const Place *operator -> () const { return &**this; } + Iterator &operator ++ () + { + ++mIter; + // This is a feature: advance position even at the end + ++mPlace.position; + if (mIter != mEnd) + mPlace.pBar = static_cast(*mIter); + else + mPlace.pBar = nullptr; + return *this; + } + + friend inline bool operator == + (const Iterator &lhs, const Iterator &rhs) + { + return lhs.mIter == rhs.mIter; + } + + friend inline bool operator != + (const Iterator &lhs, const Iterator &rhs) + { + return !(lhs == rhs); + } + + private: + friend ToolBarConfiguration; + using iterator = wxArrayPtrVoid::const_iterator; + explicit Iterator(iterator iter, iterator end) + : mIter(iter) + , mEnd(end) + { + mPlace.position = 0; + if (mIter != mEnd) + mPlace.pBar = static_cast(*mIter); + } + + iterator mIter, mEnd; + Place mPlace; + }; + + Iterator begin() const + { return Iterator { wxArrayPtrVoid::begin(), wxArrayPtrVoid::end() }; } + Iterator end() const + { return Iterator { wxArrayPtrVoid::end(), wxArrayPtrVoid::end() }; } + Position Find(const ToolBar *bar) const { return Index(const_cast(bar)); @@ -74,6 +130,7 @@ public: void Hide(ToolBar *bar); private: + Iterator FindPlace(const ToolBar *bar) const; }; class ToolDock final : public wxPanel From 3c13c6eaa6978117ec70461979dfcace56ed39cb Mon Sep 17 00:00:00 2001 From: Paul Licameli Date: Tue, 7 Jun 2016 09:57:36 -0400 Subject: [PATCH 25/41] ToolDock::OnPaint assumes less about configuration details --- src/toolbars/ToolDock.cpp | 53 +++++++++++++++++++++++++-------------- src/toolbars/ToolDock.h | 1 + 2 files changed, 35 insertions(+), 19 deletions(-) diff --git a/src/toolbars/ToolDock.cpp b/src/toolbars/ToolDock.cpp index 448e9bcca..075fed391 100644 --- a/src/toolbars/ToolDock.cpp +++ b/src/toolbars/ToolDock.cpp @@ -82,6 +82,22 @@ void ToolBarConfiguration::Hide(ToolBar *bar) Remove(bar); } +bool ToolBarConfiguration::IsRightmost(const ToolBar *bar) const +{ + auto iter = FindPlace(bar); + auto endit = end(); + if (iter == endit) + // not present + return true; + if (++iter == endit) + // Last of all + return true; + if (bar->GetRect().y != iter->pBar->GetRect().y) + // Last in its row + return true; + return false; +} + IMPLEMENT_CLASS( ToolDock, wxPanel ); //////////////////////////////////////////////////////////// @@ -507,30 +523,29 @@ void ToolDock::OnPaint( wxPaintEvent & WXUNUSED(event) ) AColor::Line(dc, 0, 0, 0, sz.GetHeight() ); // Draw the gap between each bar - int ndx, cnt = mConfiguration.GetCount(); - for( ndx = 0; ndx < cnt; ndx++ ) + for (const auto &place : GetConfiguration()) { - wxRect r = ( (ToolBar *)mConfiguration[ ndx ] )->GetRect(); + auto toolbar = place.pBar; + if (!toolbar) + continue; + + wxRect r = toolbar->GetRect(); AColor::Line( dc, - r.GetLeft(), - r.GetBottom() + 1, - sz.GetWidth(), - r.GetBottom() + 1 ); + r.GetLeft(), + r.GetBottom() + 1, + sz.GetWidth(), + r.GetBottom() + 1 ); // For all bars but the last... - if( ndx < cnt - 1 ) - { - // ...and for bars that aren't the last in a row, draw an - // horizontal gap line - if( r.y == ( (ToolBar *)mConfiguration[ ndx + 1 ] )->GetRect().y ) - { - AColor::Line(dc, - r.GetRight() + 1, - r.GetTop(), - r.GetRight() + 1, - r.GetBottom() + 1 ); - } + // ...and for bars that aren't the last in a row, draw an + // horizontal gap line + if (!mConfiguration.IsRightmost(toolbar)) { + AColor::Line(dc, + r.GetRight() + 1, + r.GetTop(), + r.GetRight() + 1, + r.GetBottom() + 1 ); } } } diff --git a/src/toolbars/ToolDock.h b/src/toolbars/ToolDock.h index 0d066a58e..4c2f0620e 100644 --- a/src/toolbars/ToolDock.h +++ b/src/toolbars/ToolDock.h @@ -129,6 +129,7 @@ public: void Show(ToolBar *bar); void Hide(ToolBar *bar); + bool IsRightmost(const ToolBar *bar) const; private: Iterator FindPlace(const ToolBar *bar) const; }; From ffb681e65833e277c72be621ea5605c39eb8236e Mon Sep 17 00:00:00 2001 From: Paul Licameli Date: Tue, 7 Jun 2016 12:37:40 -0400 Subject: [PATCH 26/41] Delegate reading and writing of toolbar configuration to new class --- src/toolbars/ToolDock.cpp | 81 ++++++++++++++++++++++++--------- src/toolbars/ToolDock.h | 15 +++++++ src/toolbars/ToolManager.cpp | 86 +++++++++++++++++------------------- 3 files changed, 117 insertions(+), 65 deletions(-) diff --git a/src/toolbars/ToolDock.cpp b/src/toolbars/ToolDock.cpp index 075fed391..69256ff25 100644 --- a/src/toolbars/ToolDock.cpp +++ b/src/toolbars/ToolDock.cpp @@ -98,6 +98,54 @@ bool ToolBarConfiguration::IsRightmost(const ToolBar *bar) const return false; } +bool ToolBarConfiguration::Read + (ToolBarConfiguration *pConfiguration, + ToolManager *pManager, + Legacy *, + ToolBar *bar, bool &visible, bool defaultVisible) +{ + bool result = true; + + if (pConfiguration) { + int ord; + gPrefs->Read( wxT("Order"), &ord, -1 ); + // Index was written 1-based + --ord; + if (ord >= ToolBarCount) + result = false; + else if (ord >= 0) + { + while(pConfiguration->size () <= ord) + pConfiguration->push_back(nullptr); + (*pConfiguration)[ord] = bar; + } + } + // Future: might remember visibility in the configuration, not forgetting + // positions of hidden bars. + gPrefs->Read( wxT("Show"), &visible, defaultVisible); + + return result; +} + +void ToolBarConfiguration::PostRead(Legacy &) +{ + auto b = wxArrayPtrVoid::begin(); + auto iter = + std::remove(b, wxArrayPtrVoid::end(), nullptr); + resize(iter - b); +} + +void ToolBarConfiguration::Write + (const ToolBarConfiguration *pConfiguration, const ToolBar *bar) +{ + if (pConfiguration) { + auto index = pConfiguration->Index(const_cast(bar)); + if (index != wxNOT_FOUND) + gPrefs->Write( wxT("Order"), 1 + index ); + } + gPrefs->Write( wxT("Show"), bar->IsVisible() ); +} + IMPLEMENT_CLASS( ToolDock, wxPanel ); //////////////////////////////////////////////////////////// @@ -140,26 +188,6 @@ ToolDock::~ToolDock() { } -// -// Returns the order of the toolbar within the dock -// -int ToolDock::GetOrder( ToolBar *bar ) -{ - int order = mConfiguration.Index( bar ); - - if( order == wxNOT_FOUND ) - { - if( bar->GetDock() == this ) - { - return 999; - } - - return 0; - } - - return order + 1; -} - // // Remove the toolbar from our control // @@ -201,6 +229,19 @@ void ToolDock::Dock( ToolBar *bar, bool deflate, ToolBarConfiguration::Position Updated(); } +// Initial docking of bars +void ToolDock::LoadConfig(ToolBar *bars[]) +{ + // Add all ordered toolbars + for(const auto &place : GetConfiguration()) { + auto bar = place.pBar; + this->Dock(bar, false); + // Show it -- hidden bars are not (yet) ever saved as part of a + // configuration + Expose( bar->GetId(), true ); + } +} + // // Layout the toolbars // diff --git a/src/toolbars/ToolDock.h b/src/toolbars/ToolDock.h index 4c2f0620e..f4a7f3b26 100644 --- a/src/toolbars/ToolDock.h +++ b/src/toolbars/ToolDock.h @@ -130,6 +130,20 @@ public: void Hide(ToolBar *bar); bool IsRightmost(const ToolBar *bar) const; + + struct Legacy { + }; + + static bool Read + (ToolBarConfiguration *pConfiguration, + ToolManager *pManager, + Legacy *pLegacy, + ToolBar *bar, bool &visible, bool defaultVisible); + void PostRead(Legacy &legacy); + + static void Write + (const ToolBarConfiguration *pConfiguration, const ToolBar *bar); + private: Iterator FindPlace(const ToolBar *bar) const; }; @@ -144,6 +158,7 @@ class ToolDock final : public wxPanel bool AcceptsFocus() const override { return false; }; + void LoadConfig(ToolBar *bars[]); void LayoutToolBars(); void Expose( int type, bool show ); int GetOrder( ToolBar *bar ); diff --git a/src/toolbars/ToolManager.cpp b/src/toolbars/ToolManager.cpp index bafb4740a..e4b4838d5 100644 --- a/src/toolbars/ToolManager.cpp +++ b/src/toolbars/ToolManager.cpp @@ -613,30 +613,23 @@ void ToolManager::ReadConfig() { wxString oldpath = gPrefs->GetPath(); wxArrayInt unordered[ DockCount ]; - int order[ DockCount ][ ToolBarCount ]; bool show[ ToolBarCount ]; int width[ ToolBarCount ]; int height[ ToolBarCount ]; int x, y; - int dock, ord, ndx; + int dock, ndx; + bool someFound { false }; #if defined(__WXMAC__) // Disable window animation wxSystemOptions::SetOption( wxMAC_WINDOW_PLAIN_TRANSITION, 1 ); #endif - // Invalidate all order entries - for( dock = 0; dock < DockCount; dock++ ) - { - for( ord = 0; ord < ToolBarCount; ord++ ) - { - order[ dock ][ ord ] = NoBarID; - } - } - // Change to the bar root gPrefs->SetPath( wxT("/GUI/ToolBars") ); + ToolBarConfiguration::Legacy topLegacy, botLegacy; + // Load and apply settings for each bar for( ndx = 0; ndx < ToolBarCount; ndx++ ) { @@ -665,9 +658,28 @@ void ToolManager::ReadConfig() #endif // Read in all the settings - gPrefs->Read( wxT("Dock"), &dock, defaultDock ); - gPrefs->Read( wxT("Order"), &ord, NoBarID ); - gPrefs->Read( wxT("Show"), &show[ ndx ], bShownByDefault); + gPrefs->Read( wxT("Dock"), &dock, -1); + const bool found = (dock != -1); + if (found) + someFound = true; + if (!found) + dock = defaultDock; + + ToolDock *d; + ToolBarConfiguration::Legacy *pLegacy; + switch(dock) + { + case TopDockID: d = mTopDock; pLegacy = &topLegacy; break; + case BotDockID: d = mBotDock; pLegacy = &botLegacy; break; + default: d = nullptr; pLegacy = nullptr; break; + } + + bool ordered = ToolBarConfiguration::Read + (d ? &d->GetConfiguration() : nullptr, + this, + pLegacy, + bar, show[ ndx ], bShownByDefault) + && found; gPrefs->Read( wxT("X"), &x, -1 ); gPrefs->Read( wxT("Y"), &y, -1 ); @@ -727,15 +739,8 @@ void ToolManager::ReadConfig() } } #endif - // Is order within range and unoccupied? - if( ( ord >= 0 ) && - ( ord < ToolBarCount ) && - ( order[ dock - 1 ][ ord ] == NoBarID ) ) - { - // Insert at ordered location - order[ dock - 1 ][ ord ] = ndx; - } - else + + if (!ordered) { // These must go at the end unordered[ dock - 1 ].Add( ndx ); @@ -776,31 +781,18 @@ void ToolManager::ReadConfig() gPrefs->SetPath( wxT("/GUI/ToolBars") ); } + mTopDock->GetConfiguration().PostRead(topLegacy); + mBotDock->GetConfiguration().PostRead(botLegacy); + // Add all toolbars to their target dock for( dock = 0; dock < DockCount; dock++ ) { ToolDock *d = ( dock + 1 == TopDockID ? mTopDock : mBotDock ); - // Add all ordered toolbars - for( ord = 0; ord < ToolBarCount; ord++ ) - { - ndx = order[ dock ][ ord ]; - - // Bypass empty slots - if( ndx != NoBarID ) - { - ToolBar *t = mBars[ ndx ]; - - // Dock it - d->Dock( t, false ); - - // Show or hide it - Expose( t->GetId(), show[ t->GetId() ] ); - } - } + d->LoadConfig(mBars); // Add all unordered toolbars - for( ord = 0; ord < (int) unordered[ dock ].GetCount(); ord++ ) + for( int ord = 0; ord < (int) unordered[ dock ].GetCount(); ord++ ) { ToolBar *t = mBars[ unordered[ dock ][ ord ] ]; @@ -819,6 +811,9 @@ void ToolManager::ReadConfig() // Reinstate original transition wxSystemOptions::SetOption( wxMAC_WINDOW_PLAIN_TRANSITION, mTransition ); #endif + + if (!someFound) + Reset(); } // @@ -846,13 +841,14 @@ void ToolManager::WriteConfig() gPrefs->SetPath( bar->GetSection() ); // Search both docks for toolbar order - int to = mTopDock->GetOrder( bar ); - int bo = mBotDock->GetOrder( bar ); + bool to = mTopDock->GetConfiguration().Contains( bar ); + bool bo = mBotDock->GetConfiguration().Contains( bar ); // Save gPrefs->Write( wxT("Dock"), (int) (to ? TopDockID : bo ? BotDockID : NoDockID )); - gPrefs->Write( wxT("Order"), to + bo ); - gPrefs->Write( wxT("Show"), IsVisible( ndx ) ); + auto dock = to ? mTopDock : bo ? mBotDock : nullptr; + ToolBarConfiguration::Write + (dock ? &dock->GetConfiguration() : nullptr, bar); wxPoint pos( -1, -1 ); wxSize sz = bar->GetSize(); From 7f920ecd0d95760ac316950a1e7a0ec06ef05f97 Mon Sep 17 00:00:00 2001 From: Paul Licameli Date: Wed, 8 Jun 2016 15:06:10 -0400 Subject: [PATCH 27/41] Starting to make ToolBarConfiguration::Position more general --- src/toolbars/ToolDock.cpp | 23 +++++++++++++-- src/toolbars/ToolDock.h | 54 +++++++++++++++++++++++++++++------- src/toolbars/ToolManager.cpp | 2 +- 3 files changed, 65 insertions(+), 14 deletions(-) diff --git a/src/toolbars/ToolDock.cpp b/src/toolbars/ToolDock.cpp index 69256ff25..c0f532115 100644 --- a/src/toolbars/ToolDock.cpp +++ b/src/toolbars/ToolDock.cpp @@ -48,6 +48,9 @@ #include "../widgets/AButton.h" #include "../widgets/Grabber.h" +const ToolBarConfiguration::Position + ToolBarConfiguration::UnspecifiedPosition { false }; + auto ToolBarConfiguration::FindPlace(const ToolBar *bar) const -> Iterator { @@ -56,12 +59,26 @@ auto ToolBarConfiguration::FindPlace(const ToolBar *bar) const ); } +auto ToolBarConfiguration::Find(const ToolBar *bar) const -> Position +{ + auto iter = FindPlace(bar); + if (iter == end()) + return UnspecifiedPosition; + else + return iter->position; +} + void ToolBarConfiguration::Insert(ToolBar *bar, Position position) { - if (position >= size() || position == UnspecifiedPosition) + if (position == UnspecifiedPosition) push_back(bar); - else - wxArrayPtrVoid::Insert(bar, position); + else { + auto index = wxArrayPtrVoid::Index(position.rightOf); + if (index == wxNOT_FOUND) + push_back(bar); + else + wxArrayPtrVoid::Insert(bar, 1 + index); + } } void ToolBarConfiguration::Remove(const ToolBar *bar) diff --git a/src/toolbars/ToolDock.h b/src/toolbars/ToolDock.h index f4a7f3b26..a19daeae9 100644 --- a/src/toolbars/ToolDock.h +++ b/src/toolbars/ToolDock.h @@ -48,12 +48,46 @@ enum class ToolBarConfiguration : public wxArrayPtrVoid { public: - using Position = int; - static const Position UnspecifiedPosition = -1; + struct Position { + ToolBar *rightOf {}; + // ToolBar *below {}; + // bool adopt {true}; + bool valid {true}; + + // Default constructor + Position() {} + + Position( + ToolBar *r /*, + ToolBar *b = nullptr, + bool shouldAdopt = true */ + ) + : rightOf{ r } // , below{ b }, adopt{ shouldAdopt } + {} + + // Constructor for the invalid value + explicit Position(bool /* dummy */) : valid{ false } {} + + friend inline bool operator == + (const Position &lhs, const Position &rhs) + { return lhs.valid == rhs.valid && + (!lhs.valid || + (lhs.rightOf == rhs.rightOf + // && lhs.below == rhs.below + // && lhs.adopt == rhs.adopt + )); + } + + friend inline bool operator != + (const Position &lhs, const Position &rhs) + { return !(lhs == rhs); } + }; + + static const Position UnspecifiedPosition; struct Place { ToolBar *pBar {}; - Position position { UnspecifiedPosition }; + Position position; }; class Iterator @@ -64,9 +98,13 @@ public: const Place *operator -> () const { return &**this; } Iterator &operator ++ () { - ++mIter; + wxASSERT(mIter != mEnd); + // This is a feature: advance position even at the end - ++mPlace.position; + mPlace.position.rightOf = mPlace.pBar; + // mPlace.position.below = nullptr; + + ++mIter; if (mIter != mEnd) mPlace.pBar = static_cast(*mIter); else @@ -93,7 +131,6 @@ public: : mIter(iter) , mEnd(end) { - mPlace.position = 0; if (mIter != mEnd) mPlace.pBar = static_cast(*mIter); } @@ -107,10 +144,7 @@ public: Iterator end() const { return Iterator { wxArrayPtrVoid::end(), wxArrayPtrVoid::end() }; } - Position Find(const ToolBar *bar) const - { - return Index(const_cast(bar)); - } + Position Find(const ToolBar *bar) const; bool Contains(const ToolBar *bar) const { diff --git a/src/toolbars/ToolManager.cpp b/src/toolbars/ToolManager.cpp index e4b4838d5..8895ba000 100644 --- a/src/toolbars/ToolManager.cpp +++ b/src/toolbars/ToolManager.cpp @@ -1344,7 +1344,7 @@ void ToolManager::DoneDragging() mDragDock = NULL; mDragBar = NULL; mPrevDock = NULL; - mPrevSlot = -1; + mPrevSlot = { ToolBarConfiguration::UnspecifiedPosition }; mLastPos.x = mBarPos.x = -1; mLastPos.y = mBarPos.y = -1; mTimer.Stop(); From 65b3d328945ee4df8f5e26f0fa6bb31ac60430f7 Mon Sep 17 00:00:00 2001 From: Paul Licameli Date: Thu, 9 Jun 2016 17:51:56 -0400 Subject: [PATCH 28/41] Tool bar configuration stores a tree structure, not a simple sequence --- src/toolbars/ToolDock.cpp | 215 ++++++++++++++++++++++++++++++----- src/toolbars/ToolDock.h | 155 ++++++++++++++++++++----- src/toolbars/ToolManager.cpp | 10 +- 3 files changed, 320 insertions(+), 60 deletions(-) diff --git a/src/toolbars/ToolDock.cpp b/src/toolbars/ToolDock.cpp index c0f532115..9bb0a7dbc 100644 --- a/src/toolbars/ToolDock.cpp +++ b/src/toolbars/ToolDock.cpp @@ -33,6 +33,7 @@ #include #include #include +#include #include #endif /* */ @@ -54,9 +55,36 @@ const ToolBarConfiguration::Position auto ToolBarConfiguration::FindPlace(const ToolBar *bar) const -> Iterator { - return std::find_if(begin(), end(), - [=](const Place &place){ return place.pBar == bar; } + auto This = const_cast(this); + return std::find_if(This->begin(), This->end(), + [=](const Place &place){ + return place.pTree->pBar == bar; + }); +} + +auto ToolBarConfiguration::FindParent(const ToolBar *bar) + -> std::pair +{ + auto findTree = [=](Forest &forest){ + return std::find_if(forest.begin(), forest.end(), + [=](const Tree &tree){ return tree.pBar == bar; }); + }; + + auto iter1 = findTree(mForest); + if (iter1 != mForest.end()) + return { &mForest, iter1 }; + + Forest::iterator result; + auto iter = std::find_if(begin(), end(), + [&](const Place &place){ + auto &children = place.pTree->children; + return (result = findTree(children)) != children.end(); + } ); + if (iter != end()) + return { &iter->pTree->children, result }; + + return { nullptr, Forest::iterator{} }; } auto ToolBarConfiguration::Find(const ToolBar *bar) const -> Position @@ -70,20 +98,105 @@ auto ToolBarConfiguration::Find(const ToolBar *bar) const -> Position void ToolBarConfiguration::Insert(ToolBar *bar, Position position) { - if (position == UnspecifiedPosition) - push_back(bar); + if (position == UnspecifiedPosition) { + // Add at the "end" of the layout + Forest *pForest = &mForest; + while (!pForest->empty()) + pForest = &pForest->back().children; + pForest->push_back( Tree {} ); + pForest->back().pBar = bar; + } else { - auto index = wxArrayPtrVoid::Index(position.rightOf); - if (index == wxNOT_FOUND) - push_back(bar); + auto pForest = &mForest; + if (position.rightOf) { + const auto parent = FindPlace(position.rightOf); + if (parent != end()) + pForest = &parent->pTree->children; + } + + const auto begin = pForest->begin(); + auto iter = begin; + const auto end = pForest->end(); + bool adopt = false; + + if (position.below) { + iter = std::find_if(begin, end, + [=](const Tree &tree){ return tree.pBar == position.below; } + ); + if (iter != end) { + ++iter; + if (iter != end) + adopt = true; + } + else + // Not found, default to topmost + iter = begin; + } else - wxArrayPtrVoid::Insert(bar, 1 + index); + adopt = (iter != end); + + // Adopt the child only if the insertion point specifies that + if (adopt && position.adopt) { + // Make new node with one child + Tree tree; + tree.pBar = bar; + tree.children.push_back(Tree{}); + + // Do adoption + auto &child = tree.children.back(); + child.pBar = iter->pBar; + child.children.swap(iter->children); + + // Put the node in the tree + (*iter).swap(tree); + } + else + pForest->insert(iter, Tree {})->pBar = bar; + } +} + +void ToolBarConfiguration::InsertAtPath + (ToolBar *bar, const std::vector &path) +{ + auto pForest = &mForest; + Tree *pTree {}; + + // Guarantee the existence of nodes + for (auto ii : path) { + Forest::size_type uu = std::max(0, ii); + pForest->resize(std::max(uu + 1, pForest->size())); + pTree = &(*pForest)[uu]; + pForest = &pTree->children; + } + + if (pTree) + pTree->pBar = bar; +} + +void ToolBarConfiguration::Remove(Forest &forest, Forest::iterator iter) +{ + Tree tree; + tree.swap(*iter); + iter = forest.erase(iter); + auto &children = tree.children; + auto cIter = children.rbegin(), cEnd = children.rend(); + while (cIter != cEnd) { + iter = forest.insert(iter, Tree{}); + (*iter).swap(*cIter); + ++cIter; } } void ToolBarConfiguration::Remove(const ToolBar *bar) { - wxArrayPtrVoid::Remove(const_cast(bar)); + auto results = FindParent(bar); + auto pForest = results.first; + if (pForest) { + // Reparent all of the children of the deleted node + auto iter = results.second; + wxASSERT(iter->pBar == bar); + Remove(*pForest, iter); + } } void ToolBarConfiguration::Show(ToolBar *bar) @@ -109,8 +222,8 @@ bool ToolBarConfiguration::IsRightmost(const ToolBar *bar) const if (++iter == endit) // Last of all return true; - if (bar->GetRect().y != iter->pBar->GetRect().y) - // Last in its row + if (bar->GetRect().y != iter->pTree->pBar->GetRect().y) + // return true; return false; } @@ -118,7 +231,7 @@ bool ToolBarConfiguration::IsRightmost(const ToolBar *bar) const bool ToolBarConfiguration::Read (ToolBarConfiguration *pConfiguration, ToolManager *pManager, - Legacy *, + Legacy *pLegacy, ToolBar *bar, bool &visible, bool defaultVisible) { bool result = true; @@ -132,11 +245,27 @@ bool ToolBarConfiguration::Read result = false; else if (ord >= 0) { - while(pConfiguration->size () <= ord) - pConfiguration->push_back(nullptr); - (*pConfiguration)[ord] = bar; + // Legacy preferences + while (pLegacy->bars.size() <= ord) + pLegacy->bars.push_back(nullptr); + pLegacy->bars[ord] = bar; + } + else { + wxString strPath; + gPrefs->Read( wxT("Path"), &strPath ); + if (!strPath.empty()) { + wxStringTokenizer toker { strPath, wxT(",") }; + std::vector path; + while(toker.HasMoreTokens()) { + auto token = toker.GetNextToken(); + auto ii = wxAtoi(token); + path.push_back(ii); + } + pConfiguration->InsertAtPath(bar, path); + } } } + // Future: might remember visibility in the configuration, not forgetting // positions of hidden bars. gPrefs->Read( wxT("Show"), &visible, defaultVisible); @@ -144,21 +273,53 @@ bool ToolBarConfiguration::Read return result; } -void ToolBarConfiguration::PostRead(Legacy &) +void ToolBarConfiguration::RemoveNulls(Forest &forest) { - auto b = wxArrayPtrVoid::begin(); - auto iter = - std::remove(b, wxArrayPtrVoid::end(), nullptr); - resize(iter - b); + for (int ii = 0; ii < forest.size(); ++ii) { + if(forest[ii].pBar == nullptr) + Remove(forest, forest.begin() + ii--); + } + + // Now do the same recursively + for (auto &tree : forest) + RemoveNulls(tree.children); +} + +void ToolBarConfiguration::PostRead(Legacy &legacy) +{ + // Be sure no nodes contain NULL, + // against the case of obsolete preferences, perhaps + RemoveNulls(mForest); + + ToolBar *prev {}; + for (auto pBar : legacy.bars) { + if (!pBar) + continue; + + Position position{ prev }; + Insert(pBar, position); + + prev = pBar; + } } void ToolBarConfiguration::Write (const ToolBarConfiguration *pConfiguration, const ToolBar *bar) { if (pConfiguration) { - auto index = pConfiguration->Index(const_cast(bar)); - if (index != wxNOT_FOUND) - gPrefs->Write( wxT("Order"), 1 + index ); + wxString strPath; + const auto cIter = pConfiguration->FindPlace(bar); + const auto path = cIter.GetPath(); + if (!path.empty()) { + auto iter = path.begin(), end = path.end(); + strPath += wxString::Format(wxT("%d"), *iter++); + while (iter != end) + strPath += wxString::Format(wxT(",%d"), *iter++); + } + gPrefs->Write(wxT("Path"), strPath); + + // Remove any legacy configuration info. + gPrefs->DeleteEntry(wxT("Order")); } gPrefs->Write( wxT("Show"), bar->IsVisible() ); } @@ -251,7 +412,7 @@ void ToolDock::LoadConfig(ToolBar *bars[]) { // Add all ordered toolbars for(const auto &place : GetConfiguration()) { - auto bar = place.pBar; + auto bar = place.pTree->pBar; this->Dock(bar, false); // Show it -- hidden bars are not (yet) ever saved as part of a // configuration @@ -286,7 +447,7 @@ void ToolDock::LayoutToolBars() for (const auto &place : GetConfiguration()) { // Cache toolbar pointer - ToolBar *ct = place.pBar; + ToolBar *ct = place.pTree->pBar; // Get and cache the toolbar sizes wxSize sz = ct->GetSize(); @@ -402,7 +563,7 @@ ToolBarConfiguration::Position else { // Cache toolbar pointer - ToolBar *ct = iter->pBar; + ToolBar *ct = iter->pTree->pBar; // Remember current bars ' dimensions sz = ct->GetSize(); @@ -583,7 +744,7 @@ void ToolDock::OnPaint( wxPaintEvent & WXUNUSED(event) ) // Draw the gap between each bar for (const auto &place : GetConfiguration()) { - auto toolbar = place.pBar; + auto toolbar = place.pTree->pBar; if (!toolbar) continue; diff --git a/src/toolbars/ToolDock.h b/src/toolbars/ToolDock.h index a19daeae9..d86864a9d 100644 --- a/src/toolbars/ToolDock.h +++ b/src/toolbars/ToolDock.h @@ -13,6 +13,8 @@ #ifndef __AUDACITY_TOOLDOCK__ #define __AUDACITY_TOOLDOCK__ +#include +#include "../MemoryX.h" // for std::move #include #include @@ -45,24 +47,32 @@ enum DockCount = 2 }; -class ToolBarConfiguration : public wxArrayPtrVoid +class ToolBarConfiguration { + struct Tree; + using Forest = std::vector; + public: + void Swap(ToolBarConfiguration &that) + { + mForest.swap(that.mForest); + } + struct Position { ToolBar *rightOf {}; - // ToolBar *below {}; - // bool adopt {true}; + ToolBar *below {}; + bool adopt {true}; bool valid {true}; // Default constructor Position() {} Position( - ToolBar *r /*, + ToolBar *r, ToolBar *b = nullptr, - bool shouldAdopt = true */ + bool shouldAdopt = true ) - : rightOf{ r } // , below{ b }, adopt{ shouldAdopt } + : rightOf{ r }, below{ b }, adopt{ shouldAdopt } {} // Constructor for the invalid value @@ -73,8 +83,8 @@ public: { return lhs.valid == rhs.valid && (!lhs.valid || (lhs.rightOf == rhs.rightOf - // && lhs.below == rhs.below - // && lhs.adopt == rhs.adopt + && lhs.below == rhs.below + && lhs.adopt == rhs.adopt )); } @@ -86,10 +96,12 @@ public: static const Position UnspecifiedPosition; struct Place { - ToolBar *pBar {}; + Tree *pTree {}; Position position; }; + // This iterator visits the nodes of the forest in pre-order, and at each + // stop, makes the parent, previous sibling, and children accessible. class Iterator : public std::iterator { @@ -98,24 +110,67 @@ public: const Place *operator -> () const { return &**this; } Iterator &operator ++ () { - wxASSERT(mIter != mEnd); - // This is a feature: advance position even at the end - mPlace.position.rightOf = mPlace.pBar; - // mPlace.position.below = nullptr; + mPlace.position = + { mPlace.pTree ? mPlace.pTree->pBar : nullptr }; + + if (!mIters.empty()) + { + auto triple = &mIters.back(); + auto &children = triple->current->children; + if (children.empty()) { + while (++triple->current == triple->end) { + mIters.pop_back(); + if (mIters.empty()) + break; + triple = &mIters.back(); + } + } + else { + auto b = children.begin(); + mIters.push_back( Triple { b, b, children.end() } ); + } + } + + if (mIters.empty()) { + mPlace.pTree = nullptr; + // Leave mPlace.position as above + } + else { + const auto &triple = mIters.back(); + mPlace.pTree = &*triple.current; + + if (mIters.size() == 1) + mPlace.position.rightOf = nullptr; + else + mPlace.position.rightOf = (mIters.rbegin() + 1)->current->pBar; + + if (triple.begin == triple.current) + mPlace.position.below = nullptr; + else + mPlace.position.below = (triple.current - 1)->pBar; + } - ++mIter; - if (mIter != mEnd) - mPlace.pBar = static_cast(*mIter); - else - mPlace.pBar = nullptr; return *this; } + // This may be called on the end iterator, and then returns empty + std::vector GetPath() const + { + std::vector path; + path.reserve(mIters.size()); + for (const auto &triple : mIters) + path.push_back(triple.current - triple.begin); + return std::move(path); + } + friend inline bool operator == (const Iterator &lhs, const Iterator &rhs) { - return lhs.mIter == rhs.mIter; + const auto &li = lhs.mIters; + const auto &ri = rhs.mIters; + return li.size() == ri.size() && + std::equal(li.begin(), li.end(), ri.begin()); } friend inline bool operator != @@ -126,23 +181,42 @@ public: private: friend ToolBarConfiguration; - using iterator = wxArrayPtrVoid::const_iterator; - explicit Iterator(iterator iter, iterator end) - : mIter(iter) - , mEnd(end) + Iterator () {} + explicit Iterator(ToolBarConfiguration &conf) { - if (mIter != mEnd) - mPlace.pBar = static_cast(*mIter); + auto &forest = conf.mForest; + if (!forest.empty()) { + auto b = forest.begin(); + mIters.push_back( Triple { b, b, forest.end() } ); + mPlace.pTree = &*b; + } } - iterator mIter, mEnd; Place mPlace; + + using FIter = Forest::iterator; + struct Triple + { + Triple (FIter b, FIter c, FIter e) + : begin{b}, current{c}, end{e} {} + FIter begin, current, end; + + friend inline bool operator == + (const Triple &lhs, const Triple &rhs) + { + // Really need only to compare current + return + // lhs.begin == rhs.begin && + lhs.current == rhs.current + // lhs.end == rhs.end + ; + } + }; + std::vector mIters; }; - Iterator begin() const - { return Iterator { wxArrayPtrVoid::begin(), wxArrayPtrVoid::end() }; } - Iterator end() const - { return Iterator { wxArrayPtrVoid::end(), wxArrayPtrVoid::end() }; } + Iterator begin() { return Iterator { *this }; } + Iterator end() const { return Iterator {}; } Position Find(const ToolBar *bar) const; @@ -154,6 +228,7 @@ public: // Default position inserts at the end void Insert(ToolBar *bar, Position position = UnspecifiedPosition); + void InsertAtPath(ToolBar *bar, const std::vector &path); void Remove(const ToolBar *bar); // Future: might allow a state that the configuration remembers @@ -166,6 +241,7 @@ public: bool IsRightmost(const ToolBar *bar) const; struct Legacy { + std::vector bars; }; static bool Read @@ -179,7 +255,26 @@ public: (const ToolBarConfiguration *pConfiguration, const ToolBar *bar); private: + + void Remove(Forest &forest, Forest::iterator iter); + void RemoveNulls(Forest &forest); + + struct Tree + { + ToolBar *pBar {}; + Forest children; + + void swap(Tree &that) + { + std::swap(pBar, that.pBar); + children.swap(that.children); + } + }; + Iterator FindPlace(const ToolBar *bar) const; + std::pair FindParent(const ToolBar *bar); + + Forest mForest; }; class ToolDock final : public wxPanel diff --git a/src/toolbars/ToolManager.cpp b/src/toolbars/ToolManager.cpp index 8895ba000..bb38712dc 100644 --- a/src/toolbars/ToolManager.cpp +++ b/src/toolbars/ToolManager.cpp @@ -862,13 +862,17 @@ void ToolManager::WriteConfig() gPrefs->Write( wxT("W"), sz.x ); gPrefs->Write( wxT("H"), sz.y ); - // Kill the bar - bar->Destroy(); - // Change back to the bar root gPrefs->SetPath( wxT("..") ); } + // Kill the bars + for( ndx = 0; ndx < ToolBarCount; ndx++ ) + { + ToolBar *bar = mBars[ ndx ]; + bar->Destroy(); + } + // Restore original config path gPrefs->SetPath( oldpath ); gPrefs->Flush(); From 3df50f81849962e4be3e31c154112e3277e23bc5 Mon Sep 17 00:00:00 2001 From: Paul Licameli Date: Fri, 10 Jun 2016 21:26:01 -0400 Subject: [PATCH 29/41] Define the default toolbar configuration (as a tree) --- src/toolbars/ToolDock.h | 6 ++++ src/toolbars/ToolManager.cpp | 53 ++++++++++++++++++++++++++++++++---- 2 files changed, 54 insertions(+), 5 deletions(-) diff --git a/src/toolbars/ToolDock.h b/src/toolbars/ToolDock.h index d86864a9d..0ae05c4f6 100644 --- a/src/toolbars/ToolDock.h +++ b/src/toolbars/ToolDock.h @@ -53,11 +53,17 @@ class ToolBarConfiguration using Forest = std::vector; public: + void Swap(ToolBarConfiguration &that) { mForest.swap(that.mForest); } + void Clear() + { + mForest.clear(); + } + struct Position { ToolBar *rightOf {}; ToolBar *below {}; diff --git a/src/toolbars/ToolManager.cpp b/src/toolbars/ToolManager.cpp index bb38712dc..fbf7361a3 100644 --- a/src/toolbars/ToolManager.cpp +++ b/src/toolbars/ToolManager.cpp @@ -498,16 +498,59 @@ ToolManager::~ToolManager() delete mDown; } +// This table describes the default configuration of the toolbars as +// a "tree" and must be kept in pre-order traversal. + +// In fact this tree is more of a broom -- nothing properly branches except +// at the root. + +// "Root" corresponds to left edge of the main window, and successive siblings +// go from top to bottom. But in practice layout may wrap this abstract +// configuration if the window size is narrow. + +static struct DefaultConfigEntry { + int barID; + int rightOf; // parent + int below; // preceding sibling +} DefaultConfigTable [] = { + // Top dock row, may wrap + { TransportBarID, NoBarID, NoBarID }, + { ToolsBarID, TransportBarID, NoBarID }, + { RecordMeterBarID, ToolsBarID, NoBarID }, + { PlayMeterBarID, RecordMeterBarID, NoBarID }, + { MixerBarID, PlayMeterBarID, NoBarID }, + { EditBarID, MixerBarID, NoBarID }, + { TranscriptionBarID, EditBarID, NoBarID }, + + // start another top dock row + { ScrubbingBarID, NoBarID, TransportBarID }, + { DeviceBarID, ScrubbingBarID, NoBarID }, + + // Hidden by default in top dock + { MeterBarID, NoBarID, NoBarID }, + + // Bottom dock + { SelectionBarID, NoBarID, NoBarID }, + + // Hidden by default in bottom dock + { SpectralSelectionBarID, NoBarID, NoBarID }, +}; + void ToolManager::Reset() { - int ndx; - // Disconnect all docked bars - for( ndx = 0; ndx < ToolBarCount; ndx++ ) + for ( const auto &entry : DefaultConfigTable ) { + int ndx = entry.barID; + ToolBar *bar = mBars[ ndx ]; + + ToolBarConfiguration::Position position { + (entry.rightOf == NoBarID) ? nullptr : mBars[ entry.rightOf ], + (entry.below == NoBarID) ? nullptr : mBars[ entry.below ] + }; + wxWindow *floater; ToolDock *dock; - ToolBar *bar = mBars[ ndx ]; bool expose = true; // Disconnect the bar @@ -558,7 +601,7 @@ void ToolManager::Reset() if( dock != NULL ) { // when we dock, we reparent, so bar is no longer a child of floater. - dock->Dock( bar, false ); + dock->Dock( bar, false, position ); Expose( ndx, expose ); //OK (and good) to DELETE floater, as bar is no longer in it. if( floater ) From 37962dd9a8bcdf6dbdafac4c6bcefeedc8c32d08 Mon Sep 17 00:00:00 2001 From: Paul Licameli Date: Fri, 10 Jun 2016 20:45:02 -0400 Subject: [PATCH 30/41] Visitors unify layout routines; now any bar can stick at lower left --- src/toolbars/ToolDock.cpp | 411 +++++++++++++++++++++++--------------- src/toolbars/ToolDock.h | 5 +- 2 files changed, 255 insertions(+), 161 deletions(-) diff --git a/src/toolbars/ToolDock.cpp b/src/toolbars/ToolDock.cpp index 9bb0a7dbc..22a70f88c 100644 --- a/src/toolbars/ToolDock.cpp +++ b/src/toolbars/ToolDock.cpp @@ -420,96 +420,234 @@ void ToolDock::LoadConfig(ToolBar *bars[]) } } -// -// Layout the toolbars -// -void ToolDock::LayoutToolBars() +class ToolDock::LayoutVisitor { - ToolBar *lt = nullptr; +public: + virtual void ModifySize + (ToolBar *ct, + const wxRect &rect, + ToolBarConfiguration::Position prevPosition, + ToolBarConfiguration::Position position, + wxSize &sz) + {} - wxRect stack[ ToolBarCount + 1 ]; - int stkcnt = 0; - int width, height; + virtual void Visit + (ToolBar *ct, wxPoint point) = 0; + virtual bool ShouldVisitSpaces() = 0; + + virtual void FinalRect + (const wxRect &rect, ToolBarConfiguration::Position finalPosition) + {} +}; + +void ToolDock::VisitLayout(LayoutVisitor &visitor) +{ // Get size of our parent since we haven't been sized yet + int width, height; GetParent()->GetClientSize( &width, &height ); width -= toolbarGap; height -= toolbarGap; - // Set initial stack entry to maximum size - stack[ 0 ].SetX( toolbarGap ); - stack[ 0 ].SetY( toolbarGap ); - // The stack width and height are the remaining width and height. - stack[ 0 ].SetWidth( width ); - stack[ 0 ].SetHeight( height ); + // Rectangle of space to allocate + wxRect main{ toolbarGap, toolbarGap, + // Allow limited width, but arbitrary height, for the root rectangle + width, std::numeric_limits::max() }; + + // For recording the nested subdivisions of the rectangle + struct Item { + int myBarID { NoBarID }; + int parentBarID { NoBarID }; + ToolBar *lastSib {}; + wxRect rect; + } layout[ ToolBarCount ]; + + ToolBar *lastRoot {}; // Process all docked and visible toolbars - for (const auto &place : GetConfiguration()) + for ( const auto &place : GetConfiguration() ) { // Cache toolbar pointer - ToolBar *ct = place.pTree->pBar; + const auto ct = place.pTree->pBar; - // Get and cache the toolbar sizes + // set up the chain of ancestors. + const auto parent = place.position.rightOf; + const auto type = ct->GetType(); + auto &newItem = layout[ type ]; + newItem.parentBarID = parent ? parent->GetType() : NoBarID; + // Mark the slots that really were visited, for final pass through + // the spaces. + newItem.myBarID = type; + + const auto parentItem = parent ? &layout[ parent->GetType() ] : nullptr; + ToolBar *prevSib; + if (!parent) { + prevSib = lastRoot; + lastRoot = ct; + } + else { + auto &sib = parentItem->lastSib; + prevSib = sib; + sib = ct; + } + ToolBarConfiguration::Position prevPosition = { parent, prevSib }; + + // Determine the size of the toolbar to fit, with advice from + // the visitor object wxSize sz = ct->GetSize(); + { + wxRect temp; + temp.SetPosition(ct->GetParent()->ClientToScreen(ct->GetPosition())); + temp.SetSize(sz); + visitor.ModifySize(ct, temp, prevPosition, place.position, sz); + } + + // Inflate the size to leave margins int tw = sz.GetWidth() + toolbarGap; int th = sz.GetHeight() + toolbarGap; - // This loop reduces stkcnt until it gives a box - // that we fit in. - while (stkcnt > 0) + // Choose the rectangle to subdivide + // Find a box that we fit in by going up the tree as needed -- + // thus when parent space is exhausted, fall back on ancestors -- + // so if the tree has too much depth for the width of the + // window, the toolbars may "wrap." + // Can always fall back to the main rectangle even if the bar is too + // wide. + auto pItem = parentItem; + auto pRect = pItem ? &pItem->rect : &main; + while (pRect != &main) { // Get out if it will fit - bool bTooWide = tw > stack[stkcnt].GetWidth(); + bool bTooWide = tw > pRect->GetWidth(); // We'd like to be able to add a tall toolbar in at the start of a row, // even if there isn't enough height for it. // If so, we'd have to at least change how we calculate 'bTooHigh'. - bool bTooHigh = th > stack[stkcnt].GetHeight(); + bool bTooHigh = th > pRect->GetHeight(); //bTooHigh &= stack[stkcnt].GetWidth() < (width - toolbarGap); //bTooHigh = false; if (!bTooWide && !bTooHigh) break; - stkcnt--; + + if (pItem->parentBarID == NoBarID) + pRect = &main; + else { + pItem = &layout[ pItem->parentBarID ]; + pRect = &pItem->rect; + } } - // The current stack entry position is where the bar - // will be placed. - const auto cpos = stack[ stkcnt ].GetPosition(); + // Place the toolbar at the upper left part of the rectangle. + const auto cpos = pRect->GetPosition(); + visitor.Visit(ct, cpos); - // Position the previous toolbar - if( lt ) - { - // Keep the tab order in order - ct->MoveAfterInTabOrder( lt ); - } + // Allocate an upper portion of the rectangle to this bar. + pRect->y += th; + pRect->height -= th; - // Place the toolbar - ct->SetPosition( wxPoint( cpos.x, cpos.y ) ); - - // Remember for next iteration - lt = ct; - - // We'll be using at least a portion of this stack entry, so - // adjust the location and size. It is possible that these - // will become zero if this entry and the toolbar have the - // same height. This is what we want as it will be destacked - // in the next iteration. - stack[ stkcnt ].SetY( stack[ stkcnt ].GetY() + th ); - stack[ stkcnt ].SetHeight( stack[ stkcnt ].GetHeight() - th ); - - // Calc the next possible horizontal location. + // A right portion of that upper portion remains available for + // descendant bars and is remembered in the layout array. int x = cpos.x + tw; - - // Add a NEW stack entry - stkcnt++; - stack[ stkcnt ].SetX( x ); - stack[ stkcnt ].SetY( cpos.y ); - stack[ stkcnt ].SetWidth( width - x ); - stack[ stkcnt ].SetHeight( th ); + newItem.rect = wxRect{ x, cpos.y, width - x, th }; } - // Set the final size of the dock window - SetMinSize( wxSize( stack[ 0 ].width, stack[ 0 ].GetY() ) ); + if (visitor.ShouldVisitSpaces()) { + // Visit the fringe where new leaves of the tree could go + + // Find the items with leftover spaces + const auto end = std::remove_if(layout, layout + ToolBarCount, + [](const Item &item){ + return item.myBarID == NoBarID || item.rect.IsEmpty(); + } + ); + // Sort top to bottom for definiteness, though perhaps not really needed + std::sort(layout, end, + [](const Item &lhs, const Item &rhs){ + return lhs.rect.y < rhs.rect.y; + } + ); + for (auto iter = layout; iter != end; ++iter) { + const auto &item = *iter; + const auto &rect = item.rect; + + auto globalRect = rect; + globalRect.SetPosition( this->ClientToScreen(rect.GetPosition()) ); + + // Let the visitor determine size + wxSize sz {}; + ToolBarConfiguration::Position + position { mBars[ item.myBarID ] }, + prevPosition {}; + visitor.ModifySize(nullptr, globalRect, prevPosition, position, sz); + int tw = sz.GetWidth() + toolbarGap; + int th = sz.GetHeight() + toolbarGap; + + // Test fit + bool bTooWide = tw > rect.GetWidth(); + bool bTooHigh = th > rect.GetHeight(); + if (!bTooWide && !bTooHigh) { + // Call visitor again to confirm the placement + const auto cpos = rect.GetPosition(); + visitor.Visit(nullptr, cpos); + } + } + } + + // Report the final bounding box of all the bars, and a position where + // you can insert a new bar at bottom left. + ToolBarConfiguration::Position finalPosition { nullptr, lastRoot }; + visitor.FinalRect( + wxRect { toolbarGap, toolbarGap, main.width, main.y }, finalPosition + ); +} + +// +// Layout the toolbars +// +void ToolDock::LayoutToolBars() +{ + struct SizeSetter final : public LayoutVisitor + { + SizeSetter (ToolDock *d) : dock{ d } {} + + void Visit + (ToolBar *bar, wxPoint point) + override + { + // Place the toolbar + if(bar) + bar->SetPosition( point ); + } + + bool ShouldVisitSpaces() override + { + return false; + } + + virtual void FinalRect + (const wxRect &rect, ToolBarConfiguration::Position) + override + { + // Set the final size of the dock window + dock->SetMinSize( rect.GetSize() ); + } + + ToolDock *dock; + } sizeSetter { + this + }; + VisitLayout(sizeSetter); + + // Set tab order + { + ToolBar *lt{}; + for ( const auto &place : GetConfiguration() ) { + auto ct = place.pTree->pBar; + if( lt ) + ct->MoveAfterInTabOrder( lt ); + lt = ct; + } + } // Clean things up Refresh( false ); @@ -522,130 +660,85 @@ void ToolDock::LayoutToolBars() ToolBarConfiguration::Position ToolDock::PositionBar( ToolBar *t, const wxPoint & pos, wxRect & rect ) { - auto tindx = ToolBarConfiguration::UnspecifiedPosition; + // Set width and size, but we must still find x and y. + rect = t->GetRect(); - wxRect stack[ ToolBarCount + 1 ]; - int stkcnt = 0; - int width, height; - - // Get size of our parent since we haven't been sized yet - GetParent()->GetClientSize( &width, &height ); - width -= toolbarGap; - height -= toolbarGap; - - // Set initial stack entry to maximum size - stack[ 0 ].SetX( toolbarGap ); - stack[ 0 ].SetY( toolbarGap ); - // The stack width and height are the remaining width and height. - stack[ 0 ].SetWidth( width ); - stack[ 0 ].SetHeight( height ); - - // Process all docked and visible toolbars - // - // Careful...slightly different from above in that we expect to - // process one more bar than is currently docked - for ( auto iter = GetConfiguration().begin(), - end = GetConfiguration().end(); - ; // iterate once more at end - ++iter ) + using Position = ToolBarConfiguration::Position; + Position result { ToolBarConfiguration::UnspecifiedPosition }; + struct Inserter : public LayoutVisitor { - wxRect sz; + struct Stop {}; - // If last entry, then it is the - if (iter == end) + Inserter(Position &p, wxRect &r, const wxPoint &pt, ToolBar *t) + : result(p), rect(r), point(pt), tb(t) + {} + + void ModifySize + (ToolBar *ct, + const wxRect &rect, + ToolBarConfiguration::Position prevPosition, + ToolBarConfiguration::Position position, + wxSize &sz) + override { - // Add the NEW bars' dimensions to the mix - rect = t->GetRect(); - sz = t->GetDockedSize(); - // This will break the loop - tindx = iter->position; - } - else - { - // Cache toolbar pointer - ToolBar *ct = iter->pTree->pBar; - - // Remember current bars ' dimensions - sz = ct->GetSize(); - // Maybe insert the NEW bar if it hasn't already been done // and is in the right place. - if (tindx == ToolBarConfiguration::UnspecifiedPosition) + + // Does the location fall within this bar? + if (rect.Contains(point)) { - wxRect r; - - // Get bar rect and make gap part of it - r.SetPosition(ct->GetParent()->ClientToScreen(ct->GetPosition())); - r.SetSize(ct->IsResizable() ? ct->GetSize() : ct->GetSize()); - r.width += toolbarGap; - r.height += toolbarGap; - - // Does the location fall within this bar? - if (r.Contains(pos) || pos.y <= r.y) - { - // Add the NEW bars' dimensions to the mix - rect = t->GetRect(); - sz = t->GetDockedSize(); - tindx = iter->position; - } + sz = tb->GetDockedSize(); + // Choose this position always, if there is a bar to displace. + // Else, only if the fit is possible. + if (ct || (sz.x < rect.width && sz.y < rect.height)) + result = position; + // Now wait until the other callback below to discover x and y } } - // Get and cache the toolbar sizes - int tw = sz.GetWidth() + toolbarGap; - int th = sz.GetHeight() + toolbarGap; - - // This loop reduces stkcnt until it gives a box - // that we fit in. - while (stkcnt > 0) + void Visit + (ToolBar *, wxPoint point) + override { - // Get out if it will fit - bool bTooWide = tw > stack[stkcnt].GetWidth(); - // We'd like to be able to add a tall toolbar in at the start of a row, - // even if there isn't enough height for it. - // If so, we'd have to at least change how we calculate 'bTooHigh'. - bool bTooHigh = th > stack[stkcnt].GetHeight(); - //bTooHigh &= stack[stkcnt].GetWidth() < (width - toolbarGap); - //bTooHigh = false; + if (result != ToolBarConfiguration::UnspecifiedPosition) { + // If we've placed it, we're done. + rect.x = point.x; + rect.y = point.y; - if (!bTooWide && !bTooHigh) - break; - stkcnt--; + throw Stop {}; + } } - // The current stack entry position is where the bar - // will be placed. - const auto cpos = stack[stkcnt].GetPosition(); - - // If we've placed it, we're done. - if (tindx != ToolBarConfiguration::UnspecifiedPosition) + bool ShouldVisitSpaces() override { - rect.x = cpos.x; - rect.y = cpos.y; - break; + return true; } - // We'll be using at least a portion of this stack entry, so - // adjust the location and size. It is possible that these - // will become zero if this entry and the toolbar have the - // same height. This is (?) what we want as it will be destacked - // in the next iteration. - stack[stkcnt].SetY(stack[stkcnt].GetY() + th); - stack[stkcnt].SetHeight(stack[stkcnt].GetHeight() - th); + void FinalRect + (const wxRect &finalRect, ToolBarConfiguration::Position finalPosition) + override + { + if (result == ToolBarConfiguration::UnspecifiedPosition) { + // Default of all other placements. + result = finalPosition; + wxPoint point { finalRect.GetLeft(), finalRect.GetBottom() }; + rect.SetPosition(point); + } + } - // Calc the next possible horizontal location. - int x = cpos.x + tw; - // Add a NEW stack entry - stkcnt++; - stack[stkcnt].SetX(x); - stack[stkcnt].SetY(cpos.y); - stack[stkcnt].SetWidth(width - x); - stack[stkcnt].SetHeight(th); - } + Position &result; + wxRect ▭ + const wxPoint point; + ToolBar *const tb; + } inserter { + result, rect, pos, t + }; + + try { VisitLayout(inserter); } catch (const Inserter::Stop&) {} // rect is decided - return tindx; + return result; } // diff --git a/src/toolbars/ToolDock.h b/src/toolbars/ToolDock.h index 0ae05c4f6..35a053000 100644 --- a/src/toolbars/ToolDock.h +++ b/src/toolbars/ToolDock.h @@ -285,8 +285,7 @@ private: class ToolDock final : public wxPanel { - - public: +public: ToolDock( ToolManager *manager, wxWindow *parent, int dockid ); ~ToolDock(); @@ -316,6 +315,8 @@ class ToolDock final : public wxPanel void OnMouseEvents(wxMouseEvent &event); private: + class LayoutVisitor; + void VisitLayout(LayoutVisitor &visitor); void Updated(); From de17c1ac3a06444c02f556960e6e1592301a375c Mon Sep 17 00:00:00 2001 From: Paul Licameli Date: Sun, 12 Jun 2016 19:10:53 -0400 Subject: [PATCH 31/41] Toolbar placements can push other bars down as well as right --- src/toolbars/ToolDock.cpp | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/src/toolbars/ToolDock.cpp b/src/toolbars/ToolDock.cpp index 22a70f88c..72a229c82 100644 --- a/src/toolbars/ToolDock.cpp +++ b/src/toolbars/ToolDock.cpp @@ -688,10 +688,16 @@ ToolBarConfiguration::Position if (rect.Contains(point)) { sz = tb->GetDockedSize(); - // Choose this position always, if there is a bar to displace. + // Choose a position always, if there is a bar to displace. // Else, only if the fit is possible. - if (ct || (sz.x < rect.width && sz.y < rect.height)) - result = position; + if (ct || (sz.x <= rect.width && sz.y <= rect.height)) { + // May choose current or previous. + if (ct && point.y < (rect.GetTop() + rect.GetBottom()) / 2) + // "Wedge" the bar into a crack alone, not adopting others + usedPrev = true, result = prevPosition, result.adopt = false; + else + result = position; + } // Now wait until the other callback below to discover x and y } } @@ -704,6 +710,8 @@ ToolBarConfiguration::Position // If we've placed it, we're done. rect.x = point.x; rect.y = point.y; + if (usedPrev) + rect.y -= tb->GetDockedSize().GetHeight() / 2; throw Stop {}; } @@ -731,6 +739,7 @@ ToolBarConfiguration::Position wxRect ▭ const wxPoint point; ToolBar *const tb; + bool usedPrev { false }; } inserter { result, rect, pos, t }; From c101f4acdb74229a4f1e773eb8e5b3e5607eda11 Mon Sep 17 00:00:00 2001 From: Paul Licameli Date: Sun, 12 Jun 2016 20:18:19 -0400 Subject: [PATCH 32/41] Enable yet more docking positions by wrapping the cofiguration --- src/toolbars/ToolDock.cpp | 41 +++++++++++++++++++++++++++++++----- src/toolbars/ToolDock.h | 13 +++++++++++- src/toolbars/ToolManager.cpp | 3 +++ src/toolbars/ToolManager.h | 1 + 4 files changed, 52 insertions(+), 6 deletions(-) diff --git a/src/toolbars/ToolDock.cpp b/src/toolbars/ToolDock.cpp index 72a229c82..b5c38a5e8 100644 --- a/src/toolbars/ToolDock.cpp +++ b/src/toolbars/ToolDock.cpp @@ -441,8 +441,12 @@ public: {} }; -void ToolDock::VisitLayout(LayoutVisitor &visitor) +void ToolDock::VisitLayout(LayoutVisitor &visitor, + ToolBarConfiguration *pWrappedConfiguration) { + if (pWrappedConfiguration) + pWrappedConfiguration->Clear(); + // Get size of our parent since we haven't been sized yet int width, height; GetParent()->GetClientSize( &width, &height ); @@ -459,10 +463,12 @@ void ToolDock::VisitLayout(LayoutVisitor &visitor) int myBarID { NoBarID }; int parentBarID { NoBarID }; ToolBar *lastSib {}; + ToolBar *lastWrappedChild {}; wxRect rect; } layout[ ToolBarCount ]; ToolBar *lastRoot {}; + ToolBar *lastWrappedRoot {}; // Process all docked and visible toolbars for ( const auto &place : GetConfiguration() ) @@ -529,14 +535,26 @@ void ToolDock::VisitLayout(LayoutVisitor &visitor) if (!bTooWide && !bTooHigh) break; - if (pItem->parentBarID == NoBarID) + if (pItem->parentBarID == NoBarID) { + pItem = nullptr; pRect = &main; + } else { pItem = &layout[ pItem->parentBarID ]; pRect = &pItem->rect; } } + // Record where the toolbar wrapped + ToolBar *& sib = pItem ? pItem->lastWrappedChild : lastWrappedRoot; + ToolBarConfiguration::Position newPosition { + pItem ? mBars[ pItem->myBarID ] : nullptr, + sib + }; + sib = ct; + if (pWrappedConfiguration) + pWrappedConfiguration->Insert(ct, newPosition); + // Place the toolbar at the upper left part of the rectangle. const auto cpos = pRect->GetPosition(); visitor.Visit(ct, cpos); @@ -576,7 +594,7 @@ void ToolDock::VisitLayout(LayoutVisitor &visitor) // Let the visitor determine size wxSize sz {}; ToolBarConfiguration::Position - position { mBars[ item.myBarID ] }, + position { mBars[ item.myBarID ], item.lastWrappedChild }, prevPosition {}; visitor.ModifySize(nullptr, globalRect, prevPosition, position, sz); int tw = sz.GetWidth() + toolbarGap; @@ -636,7 +654,7 @@ void ToolDock::LayoutToolBars() } sizeSetter { this }; - VisitLayout(sizeSetter); + VisitLayout(sizeSetter, &mWrappedConfiguration); // Set tab order { @@ -653,7 +671,6 @@ void ToolDock::LayoutToolBars() Refresh( false ); } -// // Determine the position where a NEW bar would be placed // // 'rect' will be the rectangle for the dock marker. @@ -750,6 +767,20 @@ ToolBarConfiguration::Position return result; } +void ToolDock::WrapConfiguration(ToolBarConfiguration &backup) +{ + backup.Clear(); + backup.Swap(mConfiguration); + mConfiguration.Swap(mWrappedConfiguration); +} + +void ToolDock::RestoreConfiguration(ToolBarConfiguration &backup) +{ + mWrappedConfiguration.Clear(); + mWrappedConfiguration.Swap(mConfiguration); + mConfiguration.Swap(backup); +} + // // Set the visible/hidden state of a toolbar // diff --git a/src/toolbars/ToolDock.h b/src/toolbars/ToolDock.h index 35a053000..b5a4e2dca 100644 --- a/src/toolbars/ToolDock.h +++ b/src/toolbars/ToolDock.h @@ -306,6 +306,13 @@ public: ToolBarConfiguration &GetConfiguration() { return mConfiguration; } + // backup gets old contents of the configuration; the configuration is + // set to the wrapped configuration. + void WrapConfiguration(ToolBarConfiguration &backup); + + // Reverse what was done by WrapConfiguration. + void RestoreConfiguration(ToolBarConfiguration &backup); + protected: void OnErase( wxEraseEvent & event ); @@ -316,7 +323,8 @@ public: private: class LayoutVisitor; - void VisitLayout(LayoutVisitor &visitor); + void VisitLayout(LayoutVisitor &visitor, + ToolBarConfiguration *pWrappedConfiguration = nullptr); void Updated(); @@ -328,6 +336,9 @@ public: // Stores adjacency relations that we want to realize in the dock layout ToolBarConfiguration mConfiguration; + // Configuration as modified by the constraint of the main window width + ToolBarConfiguration mWrappedConfiguration; + ToolBar *mBars[ ToolBarCount ]; public: diff --git a/src/toolbars/ToolManager.cpp b/src/toolbars/ToolManager.cpp index fbf7361a3..a21781c5d 100644 --- a/src/toolbars/ToolManager.cpp +++ b/src/toolbars/ToolManager.cpp @@ -1297,6 +1297,7 @@ void ToolManager::OnGrabber( GrabberEvent & event ) mPrevDock = dynamic_cast(mDragBar->GetParent()); wxASSERT(mPrevDock); mPrevSlot = mPrevDock->GetConfiguration().Find(mDragBar); + mPrevDock->WrapConfiguration(mPrevConfiguration); } else mPrevPosition = mDragBar->GetParent()->GetPosition(); @@ -1358,6 +1359,7 @@ void ToolManager::HandleEscapeKey() // Why don't you leave me alone? // Well, I feel so break up // I want to go home. + mPrevDock->RestoreConfiguration(mPrevConfiguration); mPrevDock->Dock( mDragBar, true, mPrevSlot ); // Done with the floater @@ -1392,6 +1394,7 @@ void ToolManager::DoneDragging() mDragBar = NULL; mPrevDock = NULL; mPrevSlot = { ToolBarConfiguration::UnspecifiedPosition }; + mPrevConfiguration.Clear(); mLastPos.x = mBarPos.x = -1; mLastPos.y = mBarPos.y = -1; mTimer.Stop(); diff --git a/src/toolbars/ToolManager.h b/src/toolbars/ToolManager.h index 44a843f08..4c4da2ece 100644 --- a/src/toolbars/ToolManager.h +++ b/src/toolbars/ToolManager.h @@ -117,6 +117,7 @@ class ToolManager final : public wxEvtHandler ToolDock *mPrevDock {}; ToolBarConfiguration::Position mPrevSlot { ToolBarConfiguration::UnspecifiedPosition }; + ToolBarConfiguration mPrevConfiguration; public: From 78e16f6e209785ae3558d5bfc2e3c5113c54aae6 Mon Sep 17 00:00:00 2001 From: Steve Daulton Date: Mon, 13 Jun 2016 08:38:54 +0100 Subject: [PATCH 33/41] include to fix Linux build --- src/toolbars/ToolDock.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/toolbars/ToolDock.cpp b/src/toolbars/ToolDock.cpp index b5c38a5e8..a01b32fa2 100644 --- a/src/toolbars/ToolDock.cpp +++ b/src/toolbars/ToolDock.cpp @@ -40,6 +40,8 @@ #include "ToolManager.h" #include "ToolDock.h" +#include + #include "../AColor.h" #include "../AllThemeResources.h" #include "../ImageManipulation.h" From c3437b1d6e6bc50270475fc97cbb063cfff86f43 Mon Sep 17 00:00:00 2001 From: Paul Licameli Date: Mon, 13 Jun 2016 09:42:24 -0400 Subject: [PATCH 34/41] Fix Windows build, and some compilation warnings --- src/toolbars/ToolDock.cpp | 25 ++++++++++++++----------- src/toolbars/ToolDock.h | 3 +-- src/toolbars/ToolManager.cpp | 3 +-- 3 files changed, 16 insertions(+), 15 deletions(-) diff --git a/src/toolbars/ToolDock.cpp b/src/toolbars/ToolDock.cpp index a01b32fa2..e74bc004c 100644 --- a/src/toolbars/ToolDock.cpp +++ b/src/toolbars/ToolDock.cpp @@ -22,6 +22,7 @@ *//**********************************************************************/ #include "../Audacity.h" +#include // For compilers that support precompilation, includes "wx/wx.h". #include @@ -33,7 +34,6 @@ #include #include #include -#include #include #endif /* */ @@ -232,7 +232,6 @@ bool ToolBarConfiguration::IsRightmost(const ToolBar *bar) const bool ToolBarConfiguration::Read (ToolBarConfiguration *pConfiguration, - ToolManager *pManager, Legacy *pLegacy, ToolBar *bar, bool &visible, bool defaultVisible) { @@ -248,7 +247,7 @@ bool ToolBarConfiguration::Read else if (ord >= 0) { // Legacy preferences - while (pLegacy->bars.size() <= ord) + while (pLegacy->bars.size() <= size_t(ord)) pLegacy->bars.push_back(nullptr); pLegacy->bars[ord] = bar; } @@ -277,7 +276,7 @@ bool ToolBarConfiguration::Read void ToolBarConfiguration::RemoveNulls(Forest &forest) { - for (int ii = 0; ii < forest.size(); ++ii) { + for (size_t ii = 0; ii < forest.size(); ++ii) { if(forest[ii].pBar == nullptr) Remove(forest, forest.begin() + ii--); } @@ -410,7 +409,7 @@ void ToolDock::Dock( ToolBar *bar, bool deflate, ToolBarConfiguration::Position } // Initial docking of bars -void ToolDock::LoadConfig(ToolBar *bars[]) +void ToolDock::LoadConfig() { // Add all ordered toolbars for(const auto &place : GetConfiguration()) { @@ -431,7 +430,9 @@ public: ToolBarConfiguration::Position prevPosition, ToolBarConfiguration::Position position, wxSize &sz) - {} + { + ct; rect; prevPosition; position; sz; + } virtual void Visit (ToolBar *ct, wxPoint point) = 0; @@ -440,7 +441,9 @@ public: virtual void FinalRect (const wxRect &rect, ToolBarConfiguration::Position finalPosition) - {} + { + rect; finalPosition; + } }; void ToolDock::VisitLayout(LayoutVisitor &visitor, @@ -473,7 +476,7 @@ void ToolDock::VisitLayout(LayoutVisitor &visitor, ToolBar *lastWrappedRoot {}; // Process all docked and visible toolbars - for ( const auto &place : GetConfiguration() ) + for ( const auto &place : this->GetConfiguration() ) { // Cache toolbar pointer const auto ct = place.pTree->pBar; @@ -550,7 +553,7 @@ void ToolDock::VisitLayout(LayoutVisitor &visitor, // Record where the toolbar wrapped ToolBar *& sib = pItem ? pItem->lastWrappedChild : lastWrappedRoot; ToolBarConfiguration::Position newPosition { - pItem ? mBars[ pItem->myBarID ] : nullptr, + pItem ? this->mBars[ pItem->myBarID ] : nullptr, sib }; sib = ct; @@ -596,7 +599,7 @@ void ToolDock::VisitLayout(LayoutVisitor &visitor, // Let the visitor determine size wxSize sz {}; ToolBarConfiguration::Position - position { mBars[ item.myBarID ], item.lastWrappedChild }, + position { this->mBars[ item.myBarID ], item.lastWrappedChild }, prevPosition {}; visitor.ModifySize(nullptr, globalRect, prevPosition, position, sz); int tw = sz.GetWidth() + toolbarGap; @@ -763,7 +766,7 @@ ToolBarConfiguration::Position result, rect, pos, t }; - try { VisitLayout(inserter); } catch (const Inserter::Stop&) {} + try { this->VisitLayout(inserter); } catch (const Inserter::Stop&) {} // rect is decided return result; diff --git a/src/toolbars/ToolDock.h b/src/toolbars/ToolDock.h index b5a4e2dca..6437c8329 100644 --- a/src/toolbars/ToolDock.h +++ b/src/toolbars/ToolDock.h @@ -252,7 +252,6 @@ public: static bool Read (ToolBarConfiguration *pConfiguration, - ToolManager *pManager, Legacy *pLegacy, ToolBar *bar, bool &visible, bool defaultVisible); void PostRead(Legacy &legacy); @@ -292,7 +291,7 @@ public: bool AcceptsFocus() const override { return false; }; - void LoadConfig(ToolBar *bars[]); + void LoadConfig(); void LayoutToolBars(); void Expose( int type, bool show ); int GetOrder( ToolBar *bar ); diff --git a/src/toolbars/ToolManager.cpp b/src/toolbars/ToolManager.cpp index a21781c5d..adfb02868 100644 --- a/src/toolbars/ToolManager.cpp +++ b/src/toolbars/ToolManager.cpp @@ -719,7 +719,6 @@ void ToolManager::ReadConfig() bool ordered = ToolBarConfiguration::Read (d ? &d->GetConfiguration() : nullptr, - this, pLegacy, bar, show[ ndx ], bShownByDefault) && found; @@ -832,7 +831,7 @@ void ToolManager::ReadConfig() { ToolDock *d = ( dock + 1 == TopDockID ? mTopDock : mBotDock ); - d->LoadConfig(mBars); + d->LoadConfig(); // Add all unordered toolbars for( int ord = 0; ord < (int) unordered[ dock ].GetCount(); ord++ ) From 1409c9507d99ea43a2e71357d787c3cd597c6740 Mon Sep 17 00:00:00 2001 From: Paul Licameli Date: Mon, 13 Jun 2016 10:06:20 -0400 Subject: [PATCH 35/41] Fix crashes when opening track control panel menu --- src/TrackPanel.h | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/src/TrackPanel.h b/src/TrackPanel.h index 51e8d0a28..25c8de333 100644 --- a/src/TrackPanel.h +++ b/src/TrackPanel.h @@ -759,20 +759,20 @@ protected: mStretchCursor, mStretchLeftCursor, mStretchRightCursor; #endif - wxMenu *mWaveTrackMenu; - size_t mChannelItemsInsertionPoint; + wxMenu *mWaveTrackMenu {}; + size_t mChannelItemsInsertionPoint {}; - wxMenu *mNoteTrackMenu; - wxMenu *mTimeTrackMenu; - wxMenu *mLabelTrackMenu; - wxMenu *mRateMenu; - wxMenu *mFormatMenu; - wxMenu *mLabelTrackInfoMenu; + wxMenu *mNoteTrackMenu {}; + wxMenu *mTimeTrackMenu {}; + wxMenu *mLabelTrackMenu {}; + wxMenu *mRateMenu {}; + wxMenu *mFormatMenu {}; + wxMenu *mLabelTrackInfoMenu {}; - wxMenu *mRulerWaveformMenu; - wxMenu *mRulerSpectrumMenu; + wxMenu *mRulerWaveformMenu {}; + wxMenu *mRulerSpectrumMenu {}; - Track *mPopupMenuTarget; + Track *mPopupMenuTarget {}; friend class TrackPanelAx; From 94249f1ea23f95eb3ff2acb0d3919a2845768280 Mon Sep 17 00:00:00 2001 From: Gale Andrews Date: Mon, 13 Jun 2016 15:51:13 +0100 Subject: [PATCH 36/41] Captialization fixes. Also renamed "Post Timer Recording Action" to "Action after Timer Recording" for greater clarity. --- src/TimerRecordDialog.cpp | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/src/TimerRecordDialog.cpp b/src/TimerRecordDialog.cpp index c6a43d683..0b7582866 100644 --- a/src/TimerRecordDialog.cpp +++ b/src/TimerRecordDialog.cpp @@ -554,9 +554,9 @@ int TimerRecordDialog::RunWaitDialog() strMsg.Printf(_("Recording start:\t\t\t%s\n") + _("Duration:\t\t\t%s\n") + _("Recording end:\t\t\t%s\n\n") + - _("Automatic Save Enabled:\t\t%s\n") + - _("Automatic Export Enabled:\t\t%s\n") + - _("Post Timer Recording Action:\t%s"), + _("Automatic Save enabled:\t\t%s\n") + + _("Automatic Export enabled:\t\t%s\n") + + _("Action after Timer Recording:\t%s"), GetDisplayDate(m_DateTime_Start).c_str(), m_TimeSpan_Duration.Format(), GetDisplayDate(m_DateTime_End).c_str(), @@ -930,7 +930,7 @@ void TimerRecordDialog::PopulateOrExchange(ShuttleGui& S) #endif m_sTimerAfterCompleteOption = arrayOptions.Item(iPostTimerRecordAction); - m_pTimerAfterCompleteChoiceCtrl = S.AddChoice(_("After Recording Completes:"), + m_pTimerAfterCompleteChoiceCtrl = S.AddChoice(_("After Recording completes:"), m_sTimerAfterCompleteOption, &m_sTimerAfterCompleteOptionsArray); } @@ -1024,9 +1024,9 @@ int TimerRecordDialog::WaitForStart() strMsg.Printf(_("Waiting to start recording at:\t%s\n") + _("Recording duration:\t\t%s\n") + _("Scheduled to stop at:\t\t%s\n\n") + - _("Automatic Save Enabled:\t\t%s\n") + - _("Automatic Export Enabled:\t\t%s\n") + - _("Post Timer Recording Action:\t%s"), + _("Automatic Save enabled:\t\t%s\n") + + _("Automatic Export enabled:\t\t%s\n") + + _("Action after Timer Recording:\t%s"), GetDisplayDate(m_DateTime_Start).c_str(), m_TimeSpan_Duration.Format(), GetDisplayDate(m_DateTime_End).c_str(), @@ -1061,10 +1061,10 @@ int TimerRecordDialog::PreActionDelay(int iActionIndex, TimerRecordCompletedActi // Build a clearer message... wxString sMessage; - sMessage.Printf(_("Timer Recording Completed.\n\n") + + sMessage.Printf(_("Timer Recording completed.\n\n") + _("Recording Saved:\t\t\t%s\n") + _("Recording Exported:\t\t%s\n") + - _("Post Timer Recording Action:\t%s"), + _("Action after Timer Recording:\t%s"), ((eCompletedActions & TR_ACTION_SAVED) ? _("Yes") : _("No")), ((eCompletedActions & TR_ACTION_EXPORTED) ? _("Yes") : _("No")), sAction); From 72c397112f221cb18f79ec5ed3934c3b2b6ff89e Mon Sep 17 00:00:00 2001 From: David Bailes Date: Thu, 9 Jun 2016 17:54:20 +0100 Subject: [PATCH 37/41] Fix that the Device toolbar can be higher than it should be. This happens on Windows 7 if the display scaling factor is set to 125% (and probably higher). This also happens on Windows 10, but only if in addition to the high scaling factor, the display scaling at high DPI is disabled on the compatibility tab of audacity.exe's properties dialog. (The behaviour on Windows 8.1 wasn't checked.) The effect of the toolbar becoming higher, is that on a row of a tooldock, no other toolbar can be in front of the Device toolbar. In void DeviceToolBar::RepositionCombos(), the desired size of the combo boxes was set to the best size. The fix is only use the x value of the best size, and leave the y value unchanged. Note that this may not be the only problem in the code which causes this problem, and so this problem may resurface in the future. --- src/toolbars/DeviceToolBar.cpp | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/src/toolbars/DeviceToolBar.cpp b/src/toolbars/DeviceToolBar.cpp index c6e351e8c..5e78b4861 100644 --- a/src/toolbars/DeviceToolBar.cpp +++ b/src/toolbars/DeviceToolBar.cpp @@ -446,15 +446,21 @@ void DeviceToolBar::RepositionCombos() return; // set up initial sizes and ratios + // Note that the y values of the desired sizes are not changed, so that the height + // of the toolbar is not changed hostRatio = kHostWidthRatio; inputRatio = kInputWidthRatio; outputRatio = kOutputWidthRatio; channelsRatio = kChannelsWidthRatio; - desiredHost = mHost->GetBestSize(); - desiredInput = mInput->GetBestSize(); - desiredOutput = mOutput->GetBestSize(); - desiredChannels = mInputChannels->GetBestSize(); + desiredHost.x = mHost->GetBestSize().x; + desiredHost.y = mHost->GetSize().y; + desiredInput.x = mInput->GetBestSize().x; + desiredInput.y = mInput->GetSize().y; + desiredOutput.x = mOutput->GetBestSize().x; + desiredOutput.y = mOutput->GetSize().y; + desiredChannels.x = mInputChannels->GetBestSize().x; + desiredChannels.y = mInputChannels->GetSize().y; // wxGtk has larger comboboxes than the other platforms. For DeviceToolBar this will cause // the height to be double because of the discrete grid layout. So we shrink it to prevent this. From 2a075558ce998da1ddfa9b0e520b87ba5a00206b Mon Sep 17 00:00:00 2001 From: Paul Licameli Date: Mon, 13 Jun 2016 19:02:06 -0400 Subject: [PATCH 38/41] Suppress duplicate tool dock points that don't give distinct results --- src/toolbars/ToolDock.cpp | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/src/toolbars/ToolDock.cpp b/src/toolbars/ToolDock.cpp index e74bc004c..72ba884f0 100644 --- a/src/toolbars/ToolDock.cpp +++ b/src/toolbars/ToolDock.cpp @@ -714,8 +714,13 @@ ToolBarConfiguration::Position // Else, only if the fit is possible. if (ct || (sz.x <= rect.width && sz.y <= rect.height)) { // May choose current or previous. - if (ct && point.y < (rect.GetTop() + rect.GetBottom()) / 2) - // "Wedge" the bar into a crack alone, not adopting others + if (ct && + (sz.y < rect.height || + point.y < (rect.GetTop() + rect.GetBottom()) / 2)) + // "Wedge" the bar into a crack alone, not adopting others, + // if either a short bar displaces a tall one, or else + // the displacing bar is at least at tall, but the pointer is + // in the upper half of the box. usedPrev = true, result = prevPosition, result.adopt = false; else result = position; From dfa91655d3c30af60f347c70106661c68911980a Mon Sep 17 00:00:00 2001 From: Paul Licameli Date: Tue, 14 Jun 2016 01:11:23 -0400 Subject: [PATCH 39/41] Bug1329, partial: Enter invokes OK button again for effects on Mac --- src/effects/Effect.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/effects/Effect.cpp b/src/effects/Effect.cpp index e1a44bde7..cdfabc258 100644 --- a/src/effects/Effect.cpp +++ b/src/effects/Effect.cpp @@ -3177,6 +3177,8 @@ void EffectUIHost::OnInitDialog(wxInitDialogEvent & evt) { focused->SelectAll(); } + + mApplyBtn->SetFocus(); } void EffectUIHost::OnErase(wxEraseEvent & WXUNUSED(evt)) From b011fc4c6b7223e9ff5c18ecfdcad98ceae570a4 Mon Sep 17 00:00:00 2001 From: David Bailes Date: Tue, 14 Jun 2016 14:18:44 +0100 Subject: [PATCH 40/41] Fix toolbar resizers being in tab traversal In commit 89e33da, the override of AcceptsFocus() was removed from the ToolBarResizer class so that ESC could cancel resizing. However this meant that the toolbar resizers were included in the tab traversal of the toolbars. The fix is the same one that was used to fix the problem with the toolbar grabbers being in the tab traversal: override AcceptsFocusFromKeyboard(), rather than AcceptsFocus(). --- src/toolbars/ToolBar.cpp | 12 +++--------- 1 file changed, 3 insertions(+), 9 deletions(-) diff --git a/src/toolbars/ToolBar.cpp b/src/toolbars/ToolBar.cpp index b949dcfd6..92c5a74b9 100644 --- a/src/toolbars/ToolBar.cpp +++ b/src/toolbars/ToolBar.cpp @@ -68,8 +68,9 @@ public: virtual ~ToolBarResizer(); // We don't need or want to accept focus. - // PRL: except for ESC key now. - // bool AcceptsFocus() const; + // Note that AcceptsFocusFromKeyboard() is overriden rather than + // AcceptsFocus(), so that resize can be cancelled by ESC + bool AcceptsFocusFromKeyboard() const override {return false;} private: void OnErase(wxEraseEvent & event); @@ -117,13 +118,6 @@ ToolBarResizer::~ToolBarResizer() ReleaseMouse(); } -/* -bool ToolBarResizer::AcceptsFocus() const -{ - return false; -} - */ - // // Handle background erasure // From 995db14fd9e664b6e44f14c8841358fc05a21d6a Mon Sep 17 00:00:00 2001 From: Paul Licameli Date: Tue, 14 Jun 2016 15:31:29 -0400 Subject: [PATCH 41/41] Bug1329, partial fix: redo it as a Mac-only change --- src/effects/Effect.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/effects/Effect.cpp b/src/effects/Effect.cpp index cdfabc258..27d16dcf4 100644 --- a/src/effects/Effect.cpp +++ b/src/effects/Effect.cpp @@ -3178,7 +3178,10 @@ void EffectUIHost::OnInitDialog(wxInitDialogEvent & evt) focused->SelectAll(); } +#ifdef __WXMAC__ // PRL: Bug1329, partial fix, but really it's the fault of + // wxWidgets 3.0.2 mApplyBtn->SetFocus(); +#endif } void EffectUIHost::OnErase(wxEraseEvent & WXUNUSED(evt))