Audacity 3.2.0
TimeToolBar.cpp
Go to the documentation of this file.
1/**********************************************************************
2
3 Audacity: A Digital Audio Editor
4
5 TimeToolBar.cpp
6
7 This program is free software; you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation; either version 2 of the License, or
10 (at your option) any later version.
11
12 *//*******************************************************************/
13
14
15
16// For compilers that support precompilation, includes "wx/wx.h".
17#include <wx/wxprec.h>
18
19#include <wx/setup.h> // for wxUSE_* macros
20
21#ifndef WX_PRECOMP
22#include <wx/sizer.h>
23#endif
24
25#include "TimeToolBar.h"
26#include "ToolManager.h"
27
28#include "AudioIO.h"
29#include "Project.h"
30#include "ProjectAudioIO.h"
32#include "ProjectRate.h"
34#include "ViewInfo.h"
35
37
39
40// Having a fixed ID for the Audio Position is helpful for
41// the Jaws screen reader script for Audacity.
42enum {
45};
46
47BEGIN_EVENT_TABLE(TimeToolBar, ToolBar)
48 EVT_COMMAND(AudioPositionID, EVT_TIMETEXTCTRL_UPDATED, TimeToolBar::OnUpdate)
49 EVT_SIZE(TimeToolBar::OnSize)
50 EVT_IDLE(TimeToolBar::OnIdle)
52
54{
55 return wxT("Time");
56}
57
59 : ToolBar(project, XO("Time"), ID(), true)
60 , mAudioTime{ nullptr }
61{
64}
65
67{
68}
69
71{
72 return BotDockID;
73}
74
76{
77 auto &toolManager = ToolManager::Get(project);
78 return *static_cast<TimeToolBar*>(toolManager.GetToolBar(ID()));
79}
80
82{
83 return Get(const_cast<AudacityProject&>(project)) ;
84}
85
87{
88 const auto &formats = ProjectNumericFormats::Get(mProject);
89
90 // Get the default time format
91 auto format = formats.GetAudioTimeFormat();
92
93 // Create the read-only time control
95 mAudioTime->SetName(XO("Audio Position"));
97
98 // Add it to the toolbar
99 Add(mAudioTime, 0, wxALIGN_CENTER | wxALL, toolbarSpacing);
100
101 // Calculate the width to height ratio
102 wxSize digitSize = mAudioTime->GetDigitSize();
103 mDigitRatio = (float)digitSize.x / digitSize.y;
104
105 // During initialization, we need to bypass some resizing to prevent the "best size"
106 // from being used as we want to ensure the saved size is used instead. See SetDocked()
107 // and OnUpdate() for more info.
108 mSettingInitialSize = true;
109 CallAfter([this]{
110 auto &formats = ProjectNumericFormats::Get(mProject);
111 // Get (and set) the saved time format
112 SetAudioTimeFormat(formats.GetAudioTimeFormat());
113
114 // During initialization, if the saved format is the same as the default,
115 // OnUpdate() will not otherwise be called but we need it to set the
116 // initial size.
118 wxCommandEvent e;
119 e.SetString(mAudioTime->GetFormatName().GET());
120 OnUpdate(e);
121 }
122 });
123
124 // Establish initial resizing limits
125 // SetResizingLimits();
127 [this](auto)
128 {
129 wxSizeEvent e;
130 OnSize(e);
131 });
132}
133
135{
136 // Since the language may have changed, we need to force an update to accommodate
137 // different length text
138 wxCommandEvent e;
139 e.SetString(mAudioTime->GetFormatName().GET());
140 OnUpdate(e);
141
142 // Language may have changed so reset label
143 SetLabel(XO("Time"));
144
145 // Give the toolbar a chance
147}
148
150{
151 // Reset
152 SetMaxSize(wxDefaultSize);
153 SetMinSize(wxDefaultSize);
154
155 // Set the default time format
158
159 // Set the default size
160 SetSize(GetInitialWidth(), 48);
161
162 // Inform others the toobar has changed
163 Updated();
164}
165
167{
168 wxSize sz = GetSize();
169
170 // Anything less than a single height bar becomes single height
171 if (sz.y <= toolbarSingle) {
172 sz.y = toolbarSingle;
173 }
174 // Otherwise it will be a double height bar
175 else {
176 sz.y = 2 * toolbarSingle + toolbarGap;
177 }
178
179 return sz;
180}
181
182void TimeToolBar::SetDocked(ToolDock *dock, bool pushed)
183{
184 // It's important to call this FIRST since it unhides the resizer control.
185 // Not doing so causes the calculated best size to be off by the width
186 // of the resizer.
187 ToolBar::SetDocked(dock, pushed);
188
189 // Recalculate the min and max limits
191
192 // When moving from floater to dock, fit to toolbar since the resizer will
193 // be mispositioned
194 if (dock) {
195 // During initialization, the desired size is already set, so do not
196 // override it with the "best size". See OnUpdate for further info.
197 if (!mSettingInitialSize) {
198 // Fit() while retaining height
199 SetSize(GetBestSize().x, GetSize().y);
200
201 // Inform others the toolbar has changed
202 Updated();
203 }
204 }
205}
206
208{
209 // Set the format if it's different from previous
211 // Simulate an update since the format has changed.
212 wxCommandEvent e;
213 e.SetString(format.GET());
214 OnUpdate(e);
215 }
216}
217
218// The intention of this is to get the resize handle in the
219// correct position, after we've let go in dragging.
221{
222 // Fit() while retaining height
223 SetSize(GetBestSize().x, GetSize().y);
224
225 // Inform others the toobar has changed
226 Updated();
227}
228
230{
231 // Reset limits
232 SetMinSize(wxDefaultSize);
233 SetMaxSize(wxDefaultSize);
234
235 // If docked we use the current bar height since it's always a single or double height
236 // toolbar. For floaters, single height toolbar is the minimum height.
237 int minH = IsDocked() ? GetSize().y : toolbarSingle;
238
239 // Get the content size given the smallest digit height we allow
240 wxSize minSize = ComputeSizing(minDigitH);
241
242 // Account for any borders added by the window manager
243 minSize.x += (mAudioTime->GetSize().x - mAudioTime->GetClientSize().x);
244
245 // Calculate the space used by other controls and sizer borders with this toolbar
246 wxSize outer = (GetSize() - GetSizer()->GetSize());
247
248 // And account for them in the width
249 minSize.x += outer.x;
250
251 // Override the height
252 minSize.y = minH;
253
254 // Get the maximum digit height we can use. This is restricted to the toolbar's
255 // current height minus any control borders
256 int digH = minH - (mAudioTime->GetSize().y - mAudioTime->GetClientSize().y);
257
258 // Get the content size using the digit height, if docked. Otherwise use the
259 // maximum digit height we allow.
260 wxSize maxSize = ComputeSizing(IsDocked() ? digH : maxDigitH);
261
262 // Account for the other controls and sizer borders within this toolbar
263 maxSize.x += outer.x;
264
265 // Account for any borders added by the window manager and +1 to keep toolbar
266 // from dropping to next smaller size when grabbing the resizer.
267 maxSize.x += (mAudioTime->GetSize().x - mAudioTime->GetClientSize().x) + 1;
268
269 // Override the height
270 maxSize.y = IsDocked() ? minH : wxDefaultCoord;
271
272 // And finally set them both
273 SetMinSize(minSize);
274 SetMaxSize(maxSize);
275}
276
278{
280 switch (evt.type) {
282 SetAudioTimeFormat(settings.GetAudioTimeFormat());
283 break;
284 default:
285 break;
286 }
287}
288
289// Called when the format drop downs is changed.
290// This causes recreation of the toolbar contents.
291void TimeToolBar::OnUpdate(wxCommandEvent &evt)
292{
293 evt.Skip(false);
294
296
297 // Reset to allow resizing to work
298 SetMinSize(wxDefaultSize);
299 SetMaxSize(wxDefaultSize);
300
301 // Save format name before recreating the controls so they resize properly
302 auto &formats = ProjectNumericFormats::Get(mProject);
303 formats.SetAudioTimeFormat(evt.GetString());
304 // Then my subscription is called
305
306 // During initialization, the desired size will have already been set at this point
307 // and the "best" size" would override it, so we simply send a size event to force
308 // the content to fit inside the toolbar.
310 mSettingInitialSize = false;
311 SendSizeEvent();
312 }
313 // Otherwise we want the toolbar to resize to fit around the content
314 else {
315 // Fit() while retaining height
316 SetSize(GetBestSize().x, GetSize().y);
317 }
318
319 // Go set the new size limits
321
322 // Inform others the toobar has changed
323 Updated();
324}
325
326void TimeToolBar::OnSize(wxSizeEvent &evt)
327{
328 evt.Skip();
329
330 // Can fire before we're ready
331 if (!mAudioTime) {
332 return;
333 }
334
335 // Make sure everything is where it's supposed to be
336 Layout();
337
338 // Get the sizer's size and remove any borders the time control might have.
339 wxSize sizerBR = GetSizer()->GetSize() - (mAudioTime->GetSize() - mAudioTime->GetClientSize());
340
341 // Get the content size of the time control. This can be different than the
342 // control itself due to borders and sizer enduced changes.
343 wxSize timeBR = mAudioTime->GetDimensions();
344
345 // Get the current digit box height
346 int h = mAudioTime->GetDigitSize().y;
347
348 // Increase current size to find the best fit within the new size
349 if (sizerBR.x >= timeBR.x && sizerBR.y >= timeBR.y) {
350 do {
351 h++;
352 timeBR = ComputeSizing(h);
353 } while (h < maxDigitH && sizerBR.x >= timeBR.x && sizerBR.y >= timeBR.y);
354 h--;
355 }
356 // In all other cases, we need to decrease current size to fit within new size
357 else if (sizerBR.x < timeBR.x || sizerBR.y < timeBR.y) {
358 do {
359 h--;
360 timeBR = ComputeSizing(h);
361 } while (h >= minDigitH && (sizerBR.x < timeBR.x || sizerBR.y < timeBR.y));
362 }
363
364 if (h != mAudioTime->GetDigitSize().y) {
366 }
367
368 // Redraw the display immediately to smooth out resizing
369 Update();
370}
371
372void TimeToolBar::OnIdle(wxIdleEvent &evt)
373{
374 evt.Skip();
375
376 double audioTime;
377
378 auto &projectAudioIO = ProjectAudioIO::Get(mProject);
379 if (projectAudioIO.IsAudioActive()) {
380 auto gAudioIO = AudioIO::Get();
381 audioTime = gAudioIO->GetStreamTime();
382 }
383 else {
384 const auto &playRegion = ViewInfo::Get(mProject).playRegion;
385 audioTime = playRegion.GetStart();
386 }
387
388 mAudioTime->SetValue(wxMax(0.0, audioTime));
389}
390
392{
393 return mAudioTime->ComputeSizing(false, digitH * mDigitRatio, digitH);
394}
395
398 {
400 }
401};
402
403namespace {
405{
407 wxT("ShowTimeTB"),
408 /* i18n-hint: Clicking this menu item shows the toolbar
409 for viewing actual time of the cursor */
410 XXO("&Time Toolbar"),
411 {
413 "ShowSelectionTB"
414 }
415};
416}
417
static const wxPoint2DDouble outer[]
Definition: ASlider.cpp:401
wxT("CloseDown"))
@ Internal
Indicates internal failure from Audacity.
END_EVENT_TABLE()
XO("Cut/Copy/Paste")
XXO("&Cut/Copy/Paste Toolbar")
EVT_COMMAND(wxID_ANY, EVT_FREQUENCYTEXTCTRL_UPDATED, LabelDialog::OnFreqUpdate) LabelDialog
Definition: LabelDialog.cpp:89
#define safenew
Definition: MemoryX.h:10
const NumericConverterType & NumericConverterType_TIME()
an object holding per-project preferred sample rate
const auto project
@ AudioPositionID
Definition: TimeToolBar.cpp:44
@ TimeBarFirstID
Definition: TimeToolBar.cpp:43
static RegisteredToolbarFactory factory
IMPLEMENT_CLASS(TimeToolBar, ToolBar)
static constexpr auto toolbarSpacing
Preferred spacing between inner toolbar elements.
Definition: ToolBar.h:57
static constexpr auto toolbarSingle
Height of a single line toolbar.
Definition: ToolBar.h:53
#define toolbarGap
Definition: ToolBar.h:63
static Settings & settings()
Definition: TrackInfo.cpp:51
The top-level handle to an Audacity project. It serves as a source of events that other objects can b...
Definition: Project.h:90
static AudioIO * Get()
Definition: AudioIO.cpp:126
static FormatterContext ProjectContext(const AudacityProject &project)
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
NumericFormatID GetFormatName() const
wxSize GetDimensions()
void SetReadOnly(bool readOnly=true)
bool SetFormatName(const NumericFormatID &formatName)
wxSize ComputeSizing(bool update=true, wxCoord digitW=0, wxCoord digitH=0)
void SetDigitSize(int width, int height)
void SetName(const TranslatableString &name)
void SetValue(double newValue)
Subscription Subscribe(Callback callback)
Connect a callback to the Publisher; later-connected are called earlier.
Definition: Observer.h:199
double GetStart() const
Definition: ViewInfo.h:129
static ProjectAudioIO & Get(AudacityProject &project)
static ProjectNumericFormats & Get(AudacityProject &project)
static const int minDigitH
Definition: TimeToolBar.h:61
void OnIdle(wxIdleEvent &evt)
void OnSize(wxSizeEvent &evt)
static TimeToolBar & Get(AudacityProject &project)
Definition: TimeToolBar.cpp:75
wxSize GetDockedSize() override
DockID DefaultDockID() const override
Which dock the toolbar defaults into. Default implementation chooses the top dock.
Definition: TimeToolBar.cpp:70
Observer::Subscription mFormatsSubscription
Definition: TimeToolBar.h:65
static const int maxDigitH
Definition: TimeToolBar.h:62
void OnFormatsChanged(ProjectNumericFormatsEvent)
void SetToDefaultSize() override
void OnUpdate(wxCommandEvent &evt)
NumericTextCtrl * mAudioTime
Definition: TimeToolBar.h:57
void SetDocked(ToolDock *dock, bool pushed) override
static Identifier ID()
Definition: TimeToolBar.cpp:53
void SetResizingLimits()
virtual ~TimeToolBar()
Definition: TimeToolBar.cpp:66
void SetAudioTimeFormat(const NumericFormatID &format)
float mDigitRatio
Definition: TimeToolBar.h:58
void ResizingDone() override
void UpdatePrefs() override
int GetInitialWidth() override
Resizable toolbars should implement these.
Definition: TimeToolBar.h:41
Observer::Subscription mFormatChangedToFitValueSubscription
Definition: TimeToolBar.h:64
void Populate() override
Definition: TimeToolBar.cpp:86
bool mSettingInitialSize
Definition: TimeToolBar.h:59
wxSize ComputeSizing(int digitH)
TimeToolBar(AudacityProject &project)
Definition: TimeToolBar.cpp:58
Works with ToolManager and ToolDock to provide a dockable window in which buttons can be placed.
Definition: ToolBar.h:73
AudacityProject & mProject
Definition: ToolBar.h:247
bool IsDocked() const
Definition: ToolBar.cpp:433
DockID
Identifies one of the docking areas for toolbars.
Definition: ToolBar.h:91
@ BotDockID
Definition: ToolBar.h:93
void Add(wxWindow *window, int proportion=0, int flag=wxALIGN_TOP, int border=0, wxObject *userData=NULL)
Definition: ToolBar.cpp:709
virtual void SetDocked(ToolDock *dock, bool pushed)
Definition: ToolBar.cpp:661
virtual void ReCreateButtons()
Definition: ToolBar.cpp:533
void SetLabel(const wxString &label) override
Definition: ToolBar.cpp:408
wxBoxSizer * GetSizer()
Definition: ToolBar.cpp:701
void UpdatePrefs() override
Definition: ToolBar.cpp:622
void Updated()
Definition: ToolBar.cpp:684
wxWindowPtr< ToolBar > Holder
Definition: ToolBar.h:77
A dynamic panel where a ToolBar can be docked.
Definition: ToolDock.h:292
static ToolManager & Get(AudacityProject &project)
PlayRegion playRegion
Definition: ViewInfo.h:217
static ViewInfo & Get(AudacityProject &project)
Definition: ViewInfo.cpp:235
void CallAfter(Action action)
Schedule an action to be done later, and in the main thread.
Definition: BasicUI.cpp:214
NUMERIC_FORMATS_API NumericFormatSymbol HoursMinsSecondsFormat()
AttachedToolBarMenuItem sAttachment
enum ProjectNumericFormatsEvent::Type type