1
0
mirror of https://github.com/cookiengineer/audacity synced 2025-09-15 07:50:22 +02:00

Merge branch 'master' into scrubbing2

This commit is contained in:
Paul Licameli 2016-06-15 01:10:54 -04:00
commit db6398c4db
41 changed files with 1371 additions and 560 deletions

View File

@ -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;
}

View File

@ -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;

View File

@ -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;

View File

@ -179,8 +179,6 @@ double GetTime(const Track *t);
void OnSortTime();
void OnSortName();
void OnToggleScrollLeftOfZero();
void OnSnapToOff();
void OnSnapToNearest();
void OnSnapToPrior();

View File

@ -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);
@ -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);

View File

@ -78,7 +78,6 @@ class Scrubber;
class ScrubbingToolBar;
class SelectionBar;
class SpectralSelectionBar;
class Toolbar;
class ToolManager;
class ToolsToolBar;
class TranscriptionToolBar;
@ -407,6 +406,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

View File

@ -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);
@ -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);

View File

@ -491,6 +491,9 @@ TrackPanel::TrackPanel(wxWindow * parent, wxWindowID id,
mAdjustLeftSelectionCursor = std::make_unique<wxCursor>(wxCURSOR_POINT_LEFT);
mAdjustRightSelectionCursor = std::make_unique<wxCursor>(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);

View File

@ -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);
@ -758,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;

View File

@ -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;

View File

@ -14,5 +14,5 @@
#include <wx/string.h>
wxString KeyStringNormalize(const wxString & key);
wxString KeyStringDisplay(const wxString & key);
wxString KeyStringDisplay(const wxString & key, bool useSpecialChars = false);
wxString KeyEventToKeyString(const wxKeyEvent & keyEvent);

View File

@ -18,6 +18,7 @@
#include "BassTreble.h"
#include <math.h>
#include <algorithm>
#include <wx/button.h>
#include <wx/intl.h>

View File

@ -3177,6 +3177,11 @@ 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))

View File

@ -188,7 +188,7 @@ void ControlToolBar::Populate()
mRecord->FollowModifierKeys();
#if wxUSE_TOOLTIPS
RegenerateToolsTooltips();
RegenerateTooltips();
wxToolTip::Enable(true);
wxToolTip::SetDelay(1000);
#endif
@ -197,47 +197,41 @@ void ControlToolBar::Populate()
ArrangeButtons();
}
void ControlToolBar::RegenerateToolsTooltips()
void ControlToolBar::RegenerateTooltips()
{
#if wxUSE_TOOLTIPS
std::vector<wxString> 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<AButton*>(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
}
@ -262,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
@ -383,7 +377,7 @@ void ControlToolBar::ReCreateButtons()
EnableDisableButtons();
RegenerateToolsTooltips();
RegenerateTooltips();
}
void ControlToolBar::Repaint( wxDC *dc )
@ -1281,6 +1275,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 +1297,7 @@ void ControlToolBar::StartScrolling()
if (!duplex)
mode = Mode::Right;
}
#endif
project->GetPlaybackScroller().Activate(mode);
}

View File

@ -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);

View File

@ -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.

View File

@ -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);

View File

@ -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<wxString> 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
}

View File

@ -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:

View File

@ -53,7 +53,7 @@ class MeterToolBar final : public ToolBar {
wxSize GetDockedSize();
private:
void RegenerateTooltips();
void RegenerateTooltips() override;
AudacityProject *mProject;
int mWhichMeters;

View File

@ -196,6 +196,8 @@ void MixerToolBar::UpdatePrefs()
// Set label to pull in language change
SetLabel(_("Mixer"));
RegenerateTooltips();
// Give base class a chance
ToolBar::UpdatePrefs();
}

View File

@ -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;

View File

@ -296,6 +296,8 @@ void SelectionBar::UpdatePrefs()
// Set label to pull in language change
SetLabel(_("Selection"));
RegenerateTooltips();
// Give base class a chance
ToolBar::UpdatePrefs();
}

View File

@ -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:

View File

@ -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();
}

View File

@ -46,6 +46,8 @@ public:
void SetBandwidthSelectionFormatName(const wxString & formatName);
void SetListener(SpectralSelectionBarListener *l);
void RegenerateTooltips() override {};
private:
void ValuesToControls();

View File

@ -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"
@ -67,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);
@ -116,13 +118,6 @@ ToolBarResizer::~ToolBarResizer()
ReleaseMouse();
}
/*
bool ToolBarResizer::AcceptsFocus() const
{
return false;
}
*/
//
// Handle background erasure
//
@ -359,7 +354,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 +362,7 @@ bool ToolBar::IsResizable()
//
// Returns the dock state of the toolbar
//
bool ToolBar::IsDocked()
bool ToolBar::IsDocked() const
{
return mDock != NULL;
}
@ -375,7 +370,7 @@ bool ToolBar::IsDocked()
//
// Returns the visibility of the toolbar
//
bool ToolBar::IsVisible()
bool ToolBar::IsVisible() const
{
return mVisible;
}
@ -761,6 +756,33 @@ void ToolBar::MakeAlternateImages(AButton &button, int idx,
button.SetAlternateImages(idx, *up, *hilite, *down, *disable);
}
void ToolBar::SetButtonToolTip
(AButton &button, const std::vector<wxString> &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)
//

View File

@ -15,6 +15,7 @@
#include "../Experimental.h"
#include <vector>
#include <wx/defs.h>
#include <wx/panel.h>
#include <wx/sizer.h>
@ -80,6 +81,9 @@ enum
ToolBarCount
};
// How may pixels padding each side of a floating toolbar
enum { ToolBarFloatMargin = 1 };
class ToolBar /* not final */ : public wxPanel
{
@ -95,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();
@ -110,9 +115,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;};
@ -146,7 +151,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<wxString> &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);

File diff suppressed because it is too large Load Diff

View File

@ -13,6 +13,8 @@
#ifndef __AUDACITY_TOOLDOCK__
#define __AUDACITY_TOOLDOCK__
#include <vector>
#include "../MemoryX.h" // for std::move
#include <wx/defs.h>
#include <wx/panel.h>
@ -45,24 +47,270 @@ enum
DockCount = 2
};
class ToolBarConfiguration
{
struct Tree;
using Forest = std::vector<Tree>;
public:
void Swap(ToolBarConfiguration &that)
{
mForest.swap(that.mForest);
}
void Clear()
{
mForest.clear();
}
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 {
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<std::forward_iterator_tag, Place>
{
public:
const Place &operator * () const { return mPlace; }
const Place *operator -> () const { return &**this; }
Iterator &operator ++ ()
{
// This is a feature: advance position even at the end
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;
}
return *this;
}
// This may be called on the end iterator, and then returns empty
std::vector<int> GetPath() const
{
std::vector<int> 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)
{
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 !=
(const Iterator &lhs, const Iterator &rhs)
{
return !(lhs == rhs);
}
private:
friend ToolBarConfiguration;
Iterator () {}
explicit Iterator(ToolBarConfiguration &conf)
{
auto &forest = conf.mForest;
if (!forest.empty()) {
auto b = forest.begin();
mIters.push_back( Triple { b, b, forest.end() } );
mPlace.pTree = &*b;
}
}
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<Triple> mIters;
};
Iterator begin() { return Iterator { *this }; }
Iterator end() const { return Iterator {}; }
Position Find(const ToolBar *bar) const;
bool Contains(const ToolBar *bar) const
{
return Find(bar) != UnspecifiedPosition;
}
// Default position inserts at the end
void Insert(ToolBar *bar,
Position position = UnspecifiedPosition);
void InsertAtPath(ToolBar *bar, const std::vector<int> &path);
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);
bool IsRightmost(const ToolBar *bar) const;
struct Legacy {
std::vector<ToolBar*> bars;
};
static bool Read
(ToolBarConfiguration *pConfiguration,
Legacy *pLegacy,
ToolBar *bar, bool &visible, bool defaultVisible);
void PostRead(Legacy &legacy);
static void Write
(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<Forest*, Forest::iterator> FindParent(const ToolBar *bar);
Forest mForest;
};
class ToolDock final : public wxPanel
{
public:
public:
ToolDock( ToolManager *manager, wxWindow *parent, int dockid );
~ToolDock();
bool AcceptsFocus() const override { return false; };
void LoadConfig();
void LayoutToolBars();
void Expose( int type, bool show );
int Find(ToolBar *bar) const;
int GetOrder( ToolBar *bar );
int GetBarCount();
void Dock( ToolBar *bar, int ndx = -1 );
void Dock( ToolBar *bar, bool deflate,
ToolBarConfiguration::Position ndx
= ToolBarConfiguration::UnspecifiedPosition);
void Undock( ToolBar *bar );
int PositionBar( ToolBar *t, wxPoint & pos, wxRect & rect );
ToolBarConfiguration::Position
PositionBar( ToolBar *t, const wxPoint & pos, wxRect & rect );
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:
@ -73,18 +321,9 @@ class ToolDock final : public wxPanel
void OnMouseEvents(wxMouseEvent &event);
private:
void ReadConfig();
void WriteConfig();
int FlowLayout( int cnt,
wxRect boxen[],
wxRect ideal[],
int i,
int x,
int y,
int width,
int height );
class LayoutVisitor;
void VisitLayout(LayoutVisitor &visitor,
ToolBarConfiguration *pWrappedConfiguration = nullptr);
void Updated();
@ -93,7 +332,12 @@ class ToolDock final : public wxPanel
ToolManager *mManager;
wxArrayPtrVoid mDockedBars;
// 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:

View File

@ -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());
@ -497,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
@ -557,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 );
dock->Dock( bar, false, position );
Expose( ndx, expose );
//OK (and good) to DELETE floater, as bar is no longer in it.
if( floater )
@ -597,6 +641,14 @@ void ToolManager::Reset()
Updated();
}
void ToolManager::RegenerateTooltips()
{
for (auto bar : mBars) {
if (bar)
bar->RegenerateTooltips();
}
}
//
// Read the toolbar states
//
@ -604,30 +656,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++ )
{
@ -656,9 +701,27 @@ 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,
pLegacy,
bar, show[ ndx ], bShownByDefault)
&& found;
gPrefs->Read( wxT("X"), &x, -1 );
gPrefs->Read( wxT("Y"), &y, -1 );
@ -718,15 +781,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 );
@ -767,36 +823,23 @@ 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 );
// Show or hide it
Expose( t->GetId(), show[ t->GetId() ] );
}
}
d->LoadConfig();
// 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 ] ];
// Dock it
d->Dock( t );
d->Dock( t, false );
// Show or hide the bar
Expose( t->GetId(), show[ t->GetId() ] );
@ -810,6 +853,9 @@ void ToolManager::ReadConfig()
// Reinstate original transition
wxSystemOptions::SetOption( wxMAC_WINDOW_PLAIN_TRANSITION, mTransition );
#endif
if (!someFound)
Reset();
}
//
@ -837,13 +883,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();
@ -857,13 +904,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();
@ -1017,7 +1068,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();
@ -1087,15 +1138,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;
}
@ -1241,7 +1295,8 @@ void ToolManager::OnGrabber( GrabberEvent & event )
if (mDragBar->IsDocked()) {
mPrevDock = dynamic_cast<ToolDock*>(mDragBar->GetParent());
wxASSERT(mPrevDock);
mPrevSlot = mPrevDock->Find(mDragBar);
mPrevSlot = mPrevDock->GetConfiguration().Find(mDragBar);
mPrevDock->WrapConfiguration(mPrevConfiguration);
}
else
mPrevPosition = mDragBar->GetParent()->GetPosition();
@ -1303,7 +1358,8 @@ 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->RestoreConfiguration(mPrevConfiguration);
mPrevDock->Dock( mDragBar, true, mPrevSlot );
// Done with the floater
mDragWindow->Destroy();
@ -1336,7 +1392,8 @@ void ToolManager::DoneDragging()
mDragDock = NULL;
mDragBar = NULL;
mPrevDock = NULL;
mPrevSlot = -1;
mPrevSlot = { ToolBarConfiguration::UnspecifiedPosition };
mPrevConfiguration.Clear();
mLastPos.x = mBarPos.x = -1;
mLastPos.y = mBarPos.y = -1;
mTimer.Stop();

View File

@ -20,7 +20,6 @@
#include "ToolDock.h"
#include "ToolBar.h"
class wxArrayPtrVoid;
class wxBitmap;
class wxCommandEvent;
class wxFrame;
@ -66,6 +65,7 @@ class ToolManager final : public wxEvtHandler
ToolDock *GetBotDock();
void Reset();
void RegenerateTooltips();
private:
@ -91,7 +91,7 @@ class ToolManager final : public wxEvtHandler
ToolDock *mDragDock;
ToolBar *mDragBar {};
wxPoint mDragOffset;
int mDragBefore;
ToolBarConfiguration::Position mDragBefore {};
wxPoint mLastPos;
wxRect mBarPos;
@ -108,7 +108,6 @@ class ToolManager final : public wxEvtHandler
bool mTransition;
#endif
wxArrayPtrVoid mDockedBars;
ToolDock *mTopDock;
ToolDock *mBotDock;
@ -116,7 +115,9 @@ class ToolManager final : public wxEvtHandler
wxPoint mPrevPosition {};
ToolDock *mPrevDock {};
int mPrevSlot {-1};
ToolBarConfiguration::Position mPrevSlot
{ ToolBarConfiguration::UnspecifiedPosition };
ToolBarConfiguration mPrevConfiguration;
public:

View File

@ -111,7 +111,7 @@ ToolsToolBar::~ToolsToolBar()
{
}
void ToolsToolBar::RegenerateToolsTooltips()
void ToolsToolBar::RegenerateTooltips()
{
// JKC:
@ -136,12 +136,28 @@ void ToolsToolBar::RegenerateToolsTooltips()
// 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<wxString> 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();
@ -150,7 +166,7 @@ void ToolsToolBar::RegenerateToolsTooltips()
void ToolsToolBar::UpdatePrefs()
{
RegenerateToolsTooltips();
RegenerateTooltips();
}
AButton * ToolsToolBar::MakeTool( teBmps eTool,
@ -183,7 +199,7 @@ void ToolsToolBar::Populate()
mTool[mCurrentTool]->PushDown();
RegenerateToolsTooltips();
RegenerateTooltips();
}
/// Gets the currently active tool

View File

@ -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);

View File

@ -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<wxString> 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"));

View File

@ -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;

View File

@ -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);

View File

@ -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);

View File

@ -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);

View File

@ -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,14 @@ 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<wxString> commands;
commands.push_back(label);
commands.push_back(commandName);
ToolBar::SetButtonToolTip(button, commands);
button.SetLabel(button.GetToolTipText());
button.UpdateStatus();
};
{
@ -2813,7 +2804,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();

View File

@ -60,10 +60,12 @@
<StringPooling>true</StringPooling>
<RuntimeLibrary>MultiThreadedDLL</RuntimeLibrary>
<FunctionLevelLinking>true</FunctionLevelLinking>
<PrecompiledHeaderOutputFile>.\$(Configuration)/audacity.pch</PrecompiledHeaderOutputFile>
<WarningLevel>Level3</WarningLevel>
<CompileAs>Default</CompileAs>
<DisableSpecificWarnings>4996;%(DisableSpecificWarnings)</DisableSpecificWarnings>
<ForcedIncludeFiles>AudacityHeaders.h;%(ForcedIncludeFiles)</ForcedIncludeFiles>
<PrecompiledHeader>Use</PrecompiledHeader>
<PrecompiledHeaderFile>AudacityHeaders.h</PrecompiledHeaderFile>
</ClCompile>
<ResourceCompile>
<PreprocessorDefinitions>NDEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
@ -121,6 +123,7 @@
<ClCompile Include="..\..\..\src\AudacityApp.cpp" />
<ClCompile Include="..\..\..\src\AudacityHeaders.cpp">
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">Create</PrecompiledHeader>
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">Create</PrecompiledHeader>
</ClCompile>
<ClCompile Include="..\..\..\src\AudacityLogger.cpp" />
<ClCompile Include="..\..\..\src\AudioIO.cpp" />