Audacity 3.2.0
ProjectStatus.cpp
Go to the documentation of this file.
1/**********************************************************************
2
3Audacity: A Digital Audio Editor
4
5ProjectStatus.h
6
7Paul Licameli
8
9**********************************************************************/
10
11#include "ProjectStatus.h"
12
13#include <algorithm>
14
15#include "Project.h"
16
17#include "AppEvents.h"
18#include "BasicUI.h"
19
21 []( AudacityProject &parent ){
22 return std::make_shared< ProjectStatus >( parent );
23 }
24};
25
27{
28 return project.AttachedObjects::Get< ProjectStatus >( key );
29}
30
32{
33 return Get( const_cast< AudacityProject & >( project ) );
34}
35
37
39 : mProject { project }
40 , mFieldChangedSubscription { ProjectStatusFieldsRegistry::Subscribe(
41 [this](const auto& project, const auto& field)
42 {
43 if (&mProject == &project)
45 }) }
46{
47}
48
50
51namespace
52{
54 {
55 static ProjectStatus::StatusWidthFunctions theFunctions;
56 return theFunctions;
57 }
58}
59
61 const StatusWidthFunction &function )
62{
63 statusWidthFunctions().emplace_back( function );
64}
65
67{
68 return statusWidthFunctions();
69}
70
72{
73 auto fieldObject = ProjectStatusFieldsRegistry::Get(field);
74 return fieldObject != nullptr && fieldObject->IsVisible(mProject) ?
75 fieldObject->GetText(mProject) :
77}
78
80{
81 auto fieldObject = ProjectStatusFieldsRegistry::Get(field);
82 if (fieldObject != nullptr)
83 fieldObject->SetText(mProject, msg);
84}
85
87{
88 ProjectStatusFieldsRegistry::Visit([this](const StatusBarFieldItem& item, const auto&)
89 { Publish(item.name); });
90}
91
93{
94 return L"state";
95}
96
98{
99 return L"main";
100}
101
103{
104 return L"rate";
105}
106
107namespace
108{
109const auto PathStart = L"StatusBarFieldRegistry";
110
111struct Message final
112{
115};
116
117struct Dispatcher final : Observer::Publisher<Message>
118{
119 void
121 {
122 Publish(Message { project, identifier });
123 }
124
126 Subscribe(std::function<void(const AudacityProject&, const StatusBarField&)>
127 handler)
128 {
130 [handler = std::move(handler)](const auto& message)
131 { handler(message.project, message.identifier); });
132 }
133
134 static Dispatcher& Get()
135 {
136 static Dispatcher dispatcher;
137 return dispatcher;
138 }
139
140 // This method is always called from the main thread
141 void NewFieldRegistered(const StatusBarField& identifier)
142 {
143 mCallEnqueued = true;
144 mNewFields.push_back(identifier);
145
147 [this]
148 {
149 if (mCallEnqueued)
150 {
152 [this]
153 {
154 for (auto& project : AllProjects {})
155 {
156 for (const auto& field : mNewFields)
158 }
159
160 mNewFields.clear();
161 mCallEnqueued = false;
162 });
163 }
164 });
165 }
166
167private:
168 std::vector<StatusBarField> mNewFields;
169 bool mCallEnqueued{ false };
170}; // struct Dispatcher
171
172} // namespace
173
175 : SingleItem { identifier }
176{
177 Dispatcher::Get().NewFieldRegistered(identifier);
178}
179
181{
182}
183
185{
186}
187
189{
190 Dispatcher::Get().Dispatch(project, name);
191}
192
195{
198 };
199 return registry;
200}
201
203 const StatusBarFieldRegistryVisitor& visitor)
204{
206 PathStart,
207 { { L"", L"state,main,rate" } },
208 };
209
211 Registry::VisitWithFunctions(visitor, &top, &Registry());
212}
213
215{
216 if (project == nullptr)
217 return Registry().size();
218
219 auto& group = Registry();
220
221 std::size_t count = 0;
222 Visit(
223 [&](const StatusBarFieldItem& item, const auto&)
224 {
225 if (item.IsVisible(*project))
226 ++count;
227 });
228
229 return count;
230}
231
233{
234 StatusBarFieldItem* result = nullptr;
235
236 Visit(
237 [&](const StatusBarFieldItem& item, const auto&)
238 {
239 if (item.name == identifier)
240 result = const_cast<StatusBarFieldItem*>(&item);
241 });
242
243 return result;
244}
245
247 const AudacityProject& project, const StatusBarField& identifier)
248{
249 int result = -1;
250 int currentIndex = 1;
251 Visit(
252 [&](const StatusBarFieldItem& item, const auto&)
253 {
254 if (!item.IsVisible(project))
255 return;
256
257 if (item.name == identifier)
258 result = currentIndex;
259 ++currentIndex;
260 });
261
262 return result;
263}
264
266{
267 Visit([&](const StatusBarFieldItem& item, const auto&)
268 { const_cast<StatusBarFieldItem&>(item).OnSize(project); });
269}
270
272 std::function<void(const AudacityProject&, const StatusBarField&)> handler)
273{
274 return Dispatcher::Get().Subscribe(std::move(handler));
275}
276
278{
279public:
280 ProjectStatusTextField(StatusBarField identifier, int defaultWidth)
281 : StatusBarFieldItem { identifier }
282 , mDefaultWidth { defaultWidth }
283 {
284 }
285
286 ~ProjectStatusTextField() override = default;
287
289 {
290 auto& projectStatus = ProjectStatus::Get(project);
291
292 auto it = projectStatus.mCurrentStatus.find(name);
293
294 if (it == projectStatus.mCurrentStatus.end())
295 {
296 projectStatus.mCurrentStatus.emplace(name, text);
298 return;
299 }
300
301 if (it->second.Translation() != text.Translation())
302 {
303 it->second = text;
305 }
306 }
307
309 {
310 auto& projectStatus = ProjectStatus::Get(project);
311
312 auto it = projectStatus.mCurrentStatus.find(name);
313 return it != projectStatus.mCurrentStatus.end() ? it->second :
315 }
316
317 int GetDefaultWidth(const AudacityProject&) const override
318 {
319 return mDefaultWidth;
320 }
321
322 bool IsVisible(const AudacityProject&) const override
323 {
324 return true;
325 }
326
327private:
328 const int mDefaultWidth;
329}; // class ProjectStatusTextField
330
332{
333 static StatusBarFieldItemRegistrator stateStatusBarField {
334 std::make_unique<ProjectStatusTextField>(StateStatusBarField(), 0),
336 };
337
338 static StatusBarFieldItemRegistrator mainStatusBarField {
339 // Main field is always expandable, hence the size is -1
340 std::make_unique<ProjectStatusTextField>(MainStatusBarField(), -1),
342 };
343
345 std::make_unique<ProjectStatusTextField>(RateStatusBarField(), 150),
347 };
348}
Toolkit-neutral facade for basic user interface services.
#define field(n, t)
Definition: ImportAUP.cpp:165
StatusBarField MainStatusBarField()
ID of the second field in the status bar. This field is expandable.
StatusBarField StateStatusBarField()
ID of the first field in the status bar. This filed is used to display playback state.
static const AudacityProject::AttachedObjects::RegisteredFactory key
StatusBarField RateStatusBarField()
ID of the third field in the status bar. This field is used to display the current rate.
const auto project
The top-level handle to an Audacity project. It serves as a source of events that other objects can b...
Definition: Project.h:90
Client code makes static instance from a factory of attachments; passes it to Get or Find as a retrie...
Definition: ClientData.h:275
An explicitly nonlocalized string, not meant for the user to see.
Definition: Identifier.h:22
const wxString & GET() const
Explicit conversion to wxString, meant to be ugly-looking and demanding of a comment why it's correct...
Definition: Identifier.h:66
An object that sends messages to an open-ended list of subscribed callbacks.
Definition: Observer.h:108
Subscription Subscribe(Callback callback)
Connect a callback to the Publisher; later-connected are called earlier.
Definition: Observer.h:199
CallbackReturn Publish(const StatusBarField &message)
Send a message to connected callbacks.
Definition: Observer.h:207
A move-only handle representing a connection to a Publisher.
Definition: Observer.h:70
int GetDefaultWidth(const AudacityProject &) const override
~ProjectStatusTextField() override=default
void SetText(AudacityProject &project, const TranslatableString &text) override
Sets the current text of the field.
ProjectStatusTextField(StatusBarField identifier, int defaultWidth)
bool IsVisible(const AudacityProject &) const override
Returns true if the field is visible in the status bar of the given project.
TranslatableString GetText(const AudacityProject &project) const
Retrieves the current text of the field.
~ProjectStatus() override
ProjectStatus(AudacityProject &project)
static const StatusWidthFunctions & GetStatusWidthFunctions()
static ProjectStatus & Get(AudacityProject &project)
void Set(const TranslatableString &msg, StatusBarField field=MainStatusBarField())
std::function< StatusWidthResult(const AudacityProject &, StatusBarField) > StatusWidthFunction
std::vector< StatusWidthFunction > StatusWidthFunctions
static struct ProjectStatus::DefaultFieldsRegistrator sDefaultFieldsRegistrator
AudacityProject & mProject
void UpdatePrefs() override
Generates classes whose instances register items at construction.
Definition: Registry.h:388
Abstract base class for status bar fields.
Definition: ProjectStatus.h:38
void DispatchFieldChanged(const AudacityProject &project)
Derived classes should call this method to notify the status bar that the field has changed.
virtual void OnSize(AudacityProject &project)
virtual ~StatusBarFieldItem()
StatusBarFieldItem(StatusBarField identifier)
virtual bool IsVisible(const AudacityProject &project) const =0
Returns true if the field is visible in the status bar of the given project.
Holds a msgid for the translation catalog; may also bind format arguments.
wxString Translation() const
void OnAppInitialized(std::function< void()> callback)
Definition: AppEvents.cpp:42
void CallAfter(Action action)
Schedule an action to be done later, and in the main thread.
Definition: BasicUI.cpp:214
Services * Get()
Fetch the global instance, or nullptr if none is yet installed.
Definition: BasicUI.cpp:202
void VisitWithFunctions(const VisitorFunctions< RegistryTraits > &visitors, const GroupItem< RegistryTraits > *pTopItem, const GroupItem< RegistryTraits > *pRegistry={}, typename RegistryTraits::ComputedItemContextType &computedItemContext=RegistryTraits::ComputedItemContextType::Instance)
Definition: Registry.h:623
auto Dispatch(Head_t< Types > &object, const TupleLike &functions, Args &&... args) -> std::enable_if_t< TypeListCheck_v< Types >, R >
Definition: TypeSwitch.h:313
ProjectStatus::StatusWidthFunctions & statusWidthFunctions()
RegisteredStatusWidthFunction(const StatusWidthFunction &function)
Registry of status bar fields.
Definition: ProjectStatus.h:83
static StatusBarFieldItem * Get(const StatusBarField &identifier)
Returns the field with the given identifier or nullptr if field is not present.
static std::size_t Count(const AudacityProject *project)
Returns the number of fields in the registry. If project is no null, only visible fields are counted.
static Registry::GroupItem< StatusBarFieldRegistryTraits > & Registry()
Returns the registry.
static void Visit(const StatusBarFieldRegistryVisitor &visitor)
Visits all fields in the registry in order.
static Observer::Subscription Subscribe(std::function< void(const AudacityProject &, const StatusBarField &)> handler)
static int GetFieldIndex(const AudacityProject &project, const StatusBarField &identifier)
Returns the zero based index of the field or -1 if field is not present.
static void OnSize(AudacityProject &project)
Handle OnSize event for all fields in the registry.
Has variadic and range constructors that check types.
Definition: Registry.h:292
const Identifier name
Definition: Registry.h:86
void NewFieldRegistered(const StatusBarField &identifier)
Observer::Subscription Subscribe(std::function< void(const AudacityProject &, const StatusBarField &)> handler)
void Dispatch(const AudacityProject &project, const StatusBarField &identifier)