mirror of
https://github.com/cookiengineer/audacity
synced 2025-05-02 08:39:46 +02:00
ProjectAudioManager doesn't use ProjectWindow, which doesn't use...
ControlToolBar, after we make a system to register functions that calculate necessary minimum widths for status bar fields. Also let Scrubbing.cpp register its own strings. Also be sure to size the status field sufficiently for "Playing at Speed".
This commit is contained in:
parent
9f61b67965
commit
68999934e0
@ -23,7 +23,6 @@ Paul Licameli split from ProjectManager.cpp
|
||||
#include "ProjectHistory.h"
|
||||
#include "ProjectSettings.h"
|
||||
#include "ProjectStatus.h"
|
||||
#include "ProjectWindow.h"
|
||||
#include "TimeTrack.h"
|
||||
#include "UndoManager.h"
|
||||
#include "toolbars/ControlToolBar.h"
|
||||
@ -49,39 +48,48 @@ const ProjectAudioManager &ProjectAudioManager::Get(
|
||||
return Get( const_cast< AudacityProject & >( project ) );
|
||||
}
|
||||
|
||||
ProjectAudioManager::ProjectAudioManager( AudacityProject &project )
|
||||
: mProject{ project }
|
||||
{
|
||||
static ProjectStatus::RegisteredStatusWidthFunction
|
||||
registerStatusWidthFunction{ StatusWidthFunction };
|
||||
}
|
||||
|
||||
ProjectAudioManager::~ProjectAudioManager() = default;
|
||||
|
||||
static wxString FormatRate( int rate )
|
||||
{
|
||||
if (rate > 0) {
|
||||
return wxString::Format(_("Actual Rate: %d"), rate);
|
||||
}
|
||||
else
|
||||
// clear the status field
|
||||
return {};
|
||||
}
|
||||
|
||||
auto ProjectAudioManager::StatusWidthFunction(
|
||||
const AudacityProject &project, StatusBarField field )
|
||||
-> ProjectStatus::StatusWidthResult
|
||||
{
|
||||
if ( field == rateStatusBarField ) {
|
||||
auto &audioManager = ProjectAudioManager::Get( project );
|
||||
int rate = audioManager.mDisplayedRate;
|
||||
return {
|
||||
{ { FormatRate( rate ) } },
|
||||
50
|
||||
};
|
||||
}
|
||||
return {};
|
||||
}
|
||||
|
||||
void ProjectAudioManager::OnAudioIORate(int rate)
|
||||
{
|
||||
auto &project = mProject;
|
||||
|
||||
// Be careful to null-check the window. We might get to this function
|
||||
// during shut-down, but a timer hasn't been told to stop sending its
|
||||
// messages yet.
|
||||
auto pWindow = ProjectWindow::Find( &project );
|
||||
if ( !pWindow )
|
||||
return;
|
||||
auto &window = *pWindow;
|
||||
mDisplayedRate = rate;
|
||||
|
||||
wxString display;
|
||||
if (rate > 0) {
|
||||
display = wxString::Format(_("Actual Rate: %d"), rate);
|
||||
}
|
||||
else
|
||||
// clear the status field
|
||||
;
|
||||
wxString display = FormatRate( rate );
|
||||
|
||||
int x, y;
|
||||
auto statusBar = window.GetStatusBar();
|
||||
statusBar->GetTextExtent(display, &x, &y);
|
||||
int widths[] = {
|
||||
0,
|
||||
ControlToolBar::Get( project ).WidthForStatusBar(statusBar),
|
||||
-1,
|
||||
x+50
|
||||
};
|
||||
statusBar->SetStatusWidths(4, widths);
|
||||
|
||||
ProjectStatus::Get( project ).Set( display, rateStatusBarField );
|
||||
}
|
||||
|
||||
|
@ -17,6 +17,8 @@ Paul Licameli split from ProjectManager.h
|
||||
class AudacityProject;
|
||||
struct AudioIOStartStreamOptions;
|
||||
|
||||
enum StatusBarField : int;
|
||||
|
||||
class ProjectAudioManager final
|
||||
: public ClientData::Base
|
||||
, public AudioIOListener
|
||||
@ -26,9 +28,7 @@ public:
|
||||
static ProjectAudioManager &Get( AudacityProject &project );
|
||||
static const ProjectAudioManager &Get( const AudacityProject &project );
|
||||
|
||||
explicit ProjectAudioManager( AudacityProject &project )
|
||||
: mProject{ project }
|
||||
{}
|
||||
explicit ProjectAudioManager( AudacityProject &project );
|
||||
ProjectAudioManager( const ProjectAudioManager & ) PROHIBITED;
|
||||
ProjectAudioManager &operator=( const ProjectAudioManager & ) PROHIBITED;
|
||||
~ProjectAudioManager() override;
|
||||
@ -77,6 +77,11 @@ private:
|
||||
bool mLooping{ false };
|
||||
bool mCutting{ false };
|
||||
bool mStopping{ false };
|
||||
|
||||
int mDisplayedRate{ 0 };
|
||||
static std::pair< std::vector< wxString >, unsigned >
|
||||
StatusWidthFunction(
|
||||
const AudacityProject &project, StatusBarField field);
|
||||
};
|
||||
|
||||
AudioIOStartStreamOptions DefaultPlayOptions( AudacityProject &project );
|
||||
|
@ -838,6 +838,8 @@ void ProjectManager::OnStatusChange( wxCommandEvent &evt )
|
||||
return;
|
||||
auto &window = *pWindow;
|
||||
|
||||
window.UpdateStatusWidths();
|
||||
|
||||
auto field = static_cast<StatusBarField>( evt.GetInt() );
|
||||
const auto &msg = ProjectStatus::Get( project ).Get( field );
|
||||
window.GetStatusBar()->SetStatusText(msg, field);
|
||||
|
@ -37,6 +37,26 @@ ProjectStatus::ProjectStatus( AudacityProject &project )
|
||||
|
||||
ProjectStatus::~ProjectStatus() = default;
|
||||
|
||||
namespace
|
||||
{
|
||||
ProjectStatus::StatusWidthFunctions &statusWidthFunctions()
|
||||
{
|
||||
static ProjectStatus::StatusWidthFunctions theFunctions;
|
||||
return theFunctions;
|
||||
}
|
||||
}
|
||||
|
||||
ProjectStatus::RegisteredStatusWidthFunction::RegisteredStatusWidthFunction(
|
||||
const StatusWidthFunction &function )
|
||||
{
|
||||
statusWidthFunctions().emplace_back( function );
|
||||
}
|
||||
|
||||
auto ProjectStatus::GetStatusWidthFunctions() -> const StatusWidthFunctions &
|
||||
{
|
||||
return statusWidthFunctions();
|
||||
}
|
||||
|
||||
const wxString &ProjectStatus::Get( StatusBarField field ) const
|
||||
{
|
||||
return mLastStatusMessages[ field - 1 ];
|
||||
|
@ -12,10 +12,13 @@ Paul Licameli
|
||||
#define __AUDACITY_PROJECT_STATUS__
|
||||
#endif
|
||||
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
#include <wx/event.h> // to declare custom event type
|
||||
#include "ClientData.h" // to inherit
|
||||
|
||||
class AudacityProject;
|
||||
class wxString;
|
||||
class wxWindow;
|
||||
|
||||
enum StatusBarField : int {
|
||||
@ -43,6 +46,24 @@ public:
|
||||
ProjectStatus &operator= ( const ProjectStatus & ) = delete;
|
||||
~ProjectStatus() override;
|
||||
|
||||
// Type of a function to report translated strings, and also report an extra
|
||||
// margin, to request that the corresponding field of the status bar should
|
||||
// be wide enough to contain any of those strings plus the margin.
|
||||
using StatusWidthResult = std::pair< std::vector<wxString>, unsigned >;
|
||||
using StatusWidthFunction = std::function<
|
||||
StatusWidthResult( const AudacityProject &, StatusBarField )
|
||||
>;
|
||||
using StatusWidthFunctions = std::vector< StatusWidthFunction >;
|
||||
|
||||
// Typically a static instance of this struct is used.
|
||||
struct RegisteredStatusWidthFunction
|
||||
{
|
||||
explicit
|
||||
RegisteredStatusWidthFunction( const StatusWidthFunction &function );
|
||||
};
|
||||
|
||||
static const StatusWidthFunctions &GetStatusWidthFunctions();
|
||||
|
||||
const wxString &Get( StatusBarField field = mainStatusBarField ) const;
|
||||
void Set(const wxString &msg,
|
||||
StatusBarField field = mainStatusBarField);
|
||||
|
@ -27,7 +27,6 @@ Paul Licameli split from AudacityProject.cpp
|
||||
#include "WaveTrack.h"
|
||||
#include "prefs/ThemePrefs.h"
|
||||
#include "prefs/TracksPrefs.h"
|
||||
#include "toolbars/ControlToolBar.h"
|
||||
#include "toolbars/ToolManager.h"
|
||||
#include "tracks/ui/Scrubbing.h"
|
||||
#include "tracks/ui/TrackView.h"
|
||||
@ -815,13 +814,7 @@ void ProjectWindow::Init()
|
||||
#endif
|
||||
mIconized = false;
|
||||
|
||||
int widths[] = {
|
||||
0,
|
||||
ControlToolBar::Get( project ).WidthForStatusBar(statusBar),
|
||||
-1,
|
||||
150
|
||||
};
|
||||
statusBar->SetStatusWidths(4, widths);
|
||||
UpdateStatusWidths();
|
||||
wxString msg = wxString::Format(_("Welcome to Audacity version %s"),
|
||||
AUDACITY_VERSION_STRING);
|
||||
statusBar->SetStatusText(msg, mainStatusBarField);
|
||||
@ -1341,6 +1334,33 @@ bool ProjectWindow::IsIconized() const
|
||||
return mIconized;
|
||||
}
|
||||
|
||||
void ProjectWindow::UpdateStatusWidths()
|
||||
{
|
||||
enum { nWidths = nStatusBarFields + 1 };
|
||||
int widths[ nWidths ]{ 0 };
|
||||
widths[ rateStatusBarField ] = 150;
|
||||
const auto statusBar = GetStatusBar();
|
||||
const auto &functions = ProjectStatus::GetStatusWidthFunctions();
|
||||
// Start from 1 not 0
|
||||
// Specifying a first column always of width 0 was needed for reasons
|
||||
// I forget now
|
||||
for ( int ii = 1; ii <= nStatusBarFields; ++ii ) {
|
||||
int &width = widths[ ii ];
|
||||
for ( const auto &function : functions ) {
|
||||
auto results =
|
||||
function( mProject, static_cast< StatusBarField >( ii ) );
|
||||
for ( const auto &string : results.first ) {
|
||||
int w;
|
||||
statusBar->GetTextExtent(string, &w, nullptr);
|
||||
width = std::max<int>( width, w + results.second );
|
||||
}
|
||||
}
|
||||
}
|
||||
// The main status field is not fixed width
|
||||
widths[ mainStatusBarField ] = -1;
|
||||
statusBar->SetStatusWidths( nWidths, widths );
|
||||
}
|
||||
|
||||
void ProjectWindow::OnIconize(wxIconizeEvent &event)
|
||||
{
|
||||
//JKC: On Iconizing we get called twice. Don't know
|
||||
|
@ -53,6 +53,8 @@ public:
|
||||
wxWindow *GetMainPage() { return mMainPage; }
|
||||
wxPanel *GetTopPanel() { return mTopPanel; }
|
||||
|
||||
void UpdateStatusWidths();
|
||||
|
||||
class PlaybackScroller final : public wxEvtHandler
|
||||
{
|
||||
public:
|
||||
|
@ -103,6 +103,13 @@ BEGIN_EVENT_TABLE(ControlToolBar, ToolBar)
|
||||
EVT_IDLE(ControlToolBar::OnIdle)
|
||||
END_EVENT_TABLE()
|
||||
|
||||
static const wxString
|
||||
sStatePlay = XO("Playing")
|
||||
, sStateStop = XO("Stopped")
|
||||
, sStateRecord = XO("Recording")
|
||||
, sStatePause = XO("Paused")
|
||||
;
|
||||
|
||||
//Standard constructor
|
||||
// This was called "Control" toolbar in the GUI before - now it is "Transport".
|
||||
// Note that we use the legacy "Control" string as the section because this
|
||||
@ -118,10 +125,6 @@ ControlToolBar::ControlToolBar( AudacityProject &project )
|
||||
|
||||
/* i18n-hint: These are strings for the status bar, and indicate whether Audacity
|
||||
is playing or recording or stopped, and whether it is paused. */
|
||||
mStatePlay = XO("Playing");
|
||||
mStateStop = XO("Stopped");
|
||||
mStateRecord = XO("Recording");
|
||||
mStatePause = XO("Paused");
|
||||
}
|
||||
|
||||
ControlToolBar::~ControlToolBar()
|
||||
@ -1375,30 +1378,28 @@ void ControlToolBar::ClearCutPreviewTracks()
|
||||
}
|
||||
|
||||
// works out the width of the field in the status bar needed for the state (eg play, record pause)
|
||||
int ControlToolBar::WidthForStatusBar(wxStatusBar* const sb)
|
||||
{
|
||||
int xMax = 0;
|
||||
const auto pauseString = wxT(" ") + wxGetTranslation(mStatePause);
|
||||
static ProjectStatus::RegisteredStatusWidthFunction
|
||||
registeredStatusWidthFunction{
|
||||
[]( const AudacityProject &, StatusBarField field )
|
||||
-> ProjectStatus::StatusWidthResult
|
||||
{
|
||||
if ( field == stateStatusBarField ) {
|
||||
const auto pauseString = wxT(" ") + GetCustomTranslation(sStatePause);
|
||||
|
||||
auto update = [&] (const wxString &state) {
|
||||
int x, y;
|
||||
sb->GetTextExtent(
|
||||
wxGetTranslation(state) + pauseString + wxT("."),
|
||||
&x, &y
|
||||
);
|
||||
xMax = std::max(x, xMax);
|
||||
};
|
||||
std::vector<wxString> strings;
|
||||
for ( auto pString :
|
||||
{ &sStatePlay, &sStateStop, &sStateRecord } )
|
||||
{
|
||||
strings.push_back(
|
||||
GetCustomTranslation(*pString) + pauseString + wxT(".") );
|
||||
}
|
||||
|
||||
update(mStatePlay);
|
||||
update(mStateStop);
|
||||
update(mStateRecord);
|
||||
|
||||
// Note that Scrubbing + Paused is not allowed.
|
||||
for(const auto &state : Scrubber::GetAllUntranslatedStatusStrings())
|
||||
update(state);
|
||||
|
||||
return xMax + 30; // added constant needed because xMax isn't large enough for some reason, plus some space.
|
||||
}
|
||||
// added constant needed because xMax isn't large enough for some reason, plus some space.
|
||||
return { std::move( strings ), 30 };
|
||||
}
|
||||
return {};
|
||||
}
|
||||
};
|
||||
|
||||
wxString ControlToolBar::StateForStatusBar()
|
||||
{
|
||||
@ -1412,16 +1413,16 @@ wxString ControlToolBar::StateForStatusBar()
|
||||
if (!scrubState.empty())
|
||||
state = wxGetTranslation(scrubState);
|
||||
else if (mPlay->IsDown())
|
||||
state = wxGetTranslation(mStatePlay);
|
||||
state = wxGetTranslation(sStatePlay);
|
||||
else if (projectAudioManager.Recording())
|
||||
state = wxGetTranslation(mStateRecord);
|
||||
state = wxGetTranslation(sStateRecord);
|
||||
else
|
||||
state = wxGetTranslation(mStateStop);
|
||||
state = wxGetTranslation(sStateStop);
|
||||
|
||||
if (mPause->IsDown())
|
||||
{
|
||||
state.Append(wxT(" "));
|
||||
state.Append(wxGetTranslation(mStatePause));
|
||||
state.Append(wxGetTranslation(sStatePause));
|
||||
}
|
||||
|
||||
state.Append(wxT("."));
|
||||
|
@ -125,8 +125,6 @@ class ControlToolBar final : public ToolBar {
|
||||
void ReCreateButtons() override;
|
||||
void RegenerateTooltips() override;
|
||||
|
||||
int WidthForStatusBar(wxStatusBar* const);
|
||||
|
||||
// Starting and stopping of scrolling display
|
||||
void StartScrollingIfPreferred();
|
||||
void StartScrolling();
|
||||
@ -188,12 +186,6 @@ class ControlToolBar final : public ToolBar {
|
||||
|
||||
std::shared_ptr<TrackList> mCutPreviewTracks;
|
||||
|
||||
// strings for status bar
|
||||
wxString mStatePlay;
|
||||
wxString mStateStop;
|
||||
wxString mStateRecord;
|
||||
wxString mStatePause;
|
||||
|
||||
PlayMode mLastPlayMode{ PlayMode::normalPlay };
|
||||
|
||||
public:
|
||||
|
@ -23,6 +23,7 @@ Paul Licameli split from TrackPanel.cpp
|
||||
#include "../../ProjectAudioIO.h"
|
||||
#include "../../ProjectAudioManager.h"
|
||||
#include "../../ProjectSettings.h"
|
||||
#include "../../ProjectStatus.h"
|
||||
#include "../../Track.h"
|
||||
#include "../../TrackPanel.h"
|
||||
#include "../../ViewInfo.h"
|
||||
@ -1139,13 +1140,14 @@ END_EVENT_TABLE()
|
||||
|
||||
static_assert(nMenuItems == 3, "wrong number of items");
|
||||
|
||||
static wxString sPlayAtSpeedStatus = XO("Playing at Speed");
|
||||
|
||||
const wxString &Scrubber::GetUntranslatedStateString() const
|
||||
{
|
||||
static wxString empty;
|
||||
|
||||
if (IsSpeedPlaying()) {
|
||||
static wxString result = XO("Playing at Speed");
|
||||
return result;
|
||||
return sPlayAtSpeedStatus;
|
||||
}
|
||||
else if (HasMark()) {
|
||||
auto &item = FindMenuItem(Seeks() || TemporarilySeeks());
|
||||
@ -1168,17 +1170,28 @@ wxString Scrubber::StatusMessageForWave() const
|
||||
|
||||
|
||||
|
||||
std::vector<wxString> Scrubber::GetAllUntranslatedStatusStrings()
|
||||
{
|
||||
using namespace std;
|
||||
vector<wxString> results;
|
||||
for (const auto &item : menuItems) {
|
||||
const auto &status = item.GetStatus();
|
||||
if (!status.empty())
|
||||
results.push_back(status);
|
||||
static ProjectStatus::RegisteredStatusWidthFunction
|
||||
registeredStatusWidthFunction{
|
||||
[]( const AudacityProject &, StatusBarField field )
|
||||
-> ProjectStatus::StatusWidthResult
|
||||
{
|
||||
if ( field == stateStatusBarField ) {
|
||||
std::vector< wxString > strings;
|
||||
// Note that Scrubbing + Paused is not allowed.
|
||||
for (const auto &item : menuItems)
|
||||
strings.push_back( GetCustomTranslation( item.GetStatus() ) );
|
||||
strings.push_back(
|
||||
GetCustomTranslation( sPlayAtSpeedStatus ) +
|
||||
wxT(" ") +
|
||||
GetCustomTranslation( XO("Paused") ) +
|
||||
wxT(".")
|
||||
);
|
||||
// added constant needed because xMax isn't large enough for some reason, plus some space.
|
||||
return { std::move( strings ), 30 };
|
||||
}
|
||||
return {};
|
||||
}
|
||||
return results;
|
||||
}
|
||||
};
|
||||
|
||||
bool Scrubber::CanScrub() const
|
||||
{
|
||||
|
@ -123,9 +123,6 @@ public:
|
||||
const wxString &GetUntranslatedStateString() const;
|
||||
wxString StatusMessageForWave() const;
|
||||
|
||||
// All possible status strings.
|
||||
static std::vector<wxString> GetAllUntranslatedStatusStrings();
|
||||
|
||||
void Pause(bool paused);
|
||||
bool IsPaused() const;
|
||||
void CheckMenuItems();
|
||||
|
Loading…
x
Reference in New Issue
Block a user