forked from audacity/audacity
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathTimeToolBar.cpp
More file actions
399 lines (317 loc) · 11 KB
/
Copy pathTimeToolBar.cpp
File metadata and controls
399 lines (317 loc) · 11 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
/**********************************************************************
Audacity: A Digital Audio Editor
TimeToolBar.cpp
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
*//*******************************************************************/
#include "../Audacity.h"
// For compilers that support precompilation, includes "wx/wx.h".
#include <wx/wxprec.h>
#include <wx/setup.h> // for wxUSE_* macros
#ifndef WX_PRECOMP
#include <wx/intl.h>
#include <wx/sizer.h>
#endif
#include "TimeToolBar.h"
#include "SelectionBarListener.h"
#include "ToolManager.h"
#include "../AudioIO.h"
#include "../Project.h"
#include "../ProjectAudioIO.h"
#include "../ProjectSettings.h"
#include "../ViewInfo.h"
IMPLEMENT_CLASS(TimeToolBar, ToolBar);
// Having a fixed ID for the Audio Position is helpful for
// the Jaws screen reader script for Audacity.
enum {
TimeBarFirstID = 2800,
AudioPositionID
};
BEGIN_EVENT_TABLE(TimeToolBar, ToolBar)
EVT_COMMAND(AudioPositionID, EVT_TIMETEXTCTRL_UPDATED, TimeToolBar::OnUpdate)
EVT_SIZE(TimeToolBar::OnSize)
EVT_IDLE(TimeToolBar::OnIdle)
END_EVENT_TABLE()
TimeToolBar::TimeToolBar(AudacityProject &project)
: ToolBar(project, TimeBarID, XO("Time"), wxT("Time"), true),
mListener(NULL),
mAudioTime(NULL)
{
project.Bind(EVT_PROJECT_SETTINGS_CHANGE, &TimeToolBar::OnSettingsChanged, this);
}
TimeToolBar::~TimeToolBar()
{
}
TimeToolBar &TimeToolBar::Get(AudacityProject &project)
{
auto &toolManager = ToolManager::Get(project);
return *static_cast<TimeToolBar*>(toolManager.GetToolBar(TimeBarID));
}
const TimeToolBar &TimeToolBar::Get(const AudacityProject &project)
{
return Get(const_cast<AudacityProject&>(project)) ;
}
void TimeToolBar::Populate()
{
const auto &settings = ProjectSettings::Get(mProject);
// Get the default sample rate
auto rate = settings.GetRate();
// Get the default time format
auto format = settings.GetAudioTimeFormat();
// Create the read-only time control
mAudioTime = safenew NumericTextCtrl(this, AudioPositionID, NumericConverter::TIME, format, 0.0, rate);
mAudioTime->SetName(XO("Audio Position"));
mAudioTime->SetReadOnly(true);
// Add it to the toolbar
Add(mAudioTime, 0, wxALIGN_CENTER, 0);
// Calculate the width to height ratio
wxSize digitSize = mAudioTime->GetDigitSize();
mDigitRatio = (float)digitSize.x / digitSize.y;
// During initialization, we need to bypass some resizing to prevent the "best size"
// from being used as we want to ensure the saved size is used instead. See SetDocked()
// and OnUpdate() for more info.
mSettingInitialSize = true;
// Establish initial resizing limits
// SetResizingLimits();
}
void TimeToolBar::UpdatePrefs()
{
// Since the language may have changed, we need to force an update to accommodate
// different length text
wxCommandEvent e;
e.SetInt(mAudioTime->GetFormatIndex());
OnUpdate(e);
// Language may have changed so reset label
SetLabel(XO("Time"));
// Give the toolbar a chance
ToolBar::UpdatePrefs();
}
void TimeToolBar::SetToDefaultSize()
{
// Reset
SetMaxSize(wxDefaultSize);
SetMinSize(wxDefaultSize);
// Set the default time format
SetAudioTimeFormat(NumericConverter::HoursMinsSecondsFormat());
// Set the default size
SetSize(GetInitialWidth(), 48);
// Inform others the toobar has changed
Updated();
}
wxSize TimeToolBar::GetDockedSize()
{
wxSize sz = GetSize();
// Anything less than a single height bar becomes single height
if (sz.y <= toolbarSingle) {
sz.y = toolbarSingle;
}
// Otherwise it will be a double height bar
else {
sz.y = 2 * toolbarSingle + toolbarGap;
}
return sz;
}
void TimeToolBar::SetDocked(ToolDock *dock, bool pushed)
{
// It's important to call this FIRST since it unhides the resizer control.
// Not doing so causes the calculated best size to be off by the width
// of the resizer.
ToolBar::SetDocked(dock, pushed);
// Recalculate the min and max limits
SetResizingLimits();
// When moving from floater to dock, fit to toolbar since the resizer will
// be mispositioned
if (dock) {
// During initialization, the desired size is already set, so do not
// override it with the "best size". See OnUpdate for further info.
if (!mSettingInitialSize) {
// Fit() while retaining height
SetSize(GetBestSize().x, GetSize().y);
// Inform others the toolbar has changed
Updated();
}
}
}
void TimeToolBar::SetListener(TimeToolBarListener *l)
{
// Remember the listener
mListener = l;
// Get (and set) the saved time format
SetAudioTimeFormat(mListener->TT_GetAudioTimeFormat());
// During initialization, if the saved format is the same as the default,
// OnUpdate() will not be called and need it to set the initial size.
if (mSettingInitialSize) {
wxCommandEvent e;
e.SetInt(mAudioTime->GetFormatIndex());
OnUpdate(e);
}
}
void TimeToolBar::SetAudioTimeFormat(const NumericFormatSymbol & format)
{
// Set the format if it's different from previous
if (mAudioTime->SetFormatString(mAudioTime->GetBuiltinFormat(format))) {
// Simulate an update since the format has changed.
wxCommandEvent e;
e.SetInt(mAudioTime->GetFormatIndex());
OnUpdate(e);
}
}
// The intention of this is to get the resize handle in the
// correct position, after we've let go in dragging.
void TimeToolBar::ResizingDone()
{
// Fit() while retaining height
SetSize(GetBestSize().x, GetSize().y);
// Inform others the toobar has changed
Updated();
}
void TimeToolBar::SetResizingLimits()
{
// Reset limits
SetMinSize(wxDefaultSize);
SetMaxSize(wxDefaultSize);
// If docked we use the current bar height since it's always a single or double height
// toolbar. For floaters, single height toolbar is the minimum height.
int minH = IsDocked() ? GetSize().y : toolbarSingle;
// Get the content size given the smallest digit height we allow
wxSize minSize = ComputeSizing(minDigitH);
// Account for any borders added by the window manager
minSize.x += (mAudioTime->GetSize().x - mAudioTime->GetClientSize().x);
// Calculate the space used by other controls and sizer borders with this toolbar
wxSize outer = (GetSize() - GetSizer()->GetSize());
// And account for them in the width
minSize.x += outer.x;
// Override the height
minSize.y = minH;
// Get the maximum digit height we can use. This is restricted to the toolbar's
// current height minus any control borders
int digH = minH - (mAudioTime->GetSize().y - mAudioTime->GetClientSize().y);
// Get the content size using the digit height, if docked. Otherwise use the
// maximum digit height we allow.
wxSize maxSize = ComputeSizing(IsDocked() ? digH : maxDigitH);
// Account for the other controls and sizer borders within this toolbar
maxSize.x += outer.x;
// Account for any borders added by the window manager and +1 to keep toolbar
// from dropping to next smaller size when grabbing the resizer.
maxSize.x += (mAudioTime->GetSize().x - mAudioTime->GetClientSize().x) + 1;
// Override the height
maxSize.y = IsDocked() ? minH : wxDefaultCoord;
// And finally set them both
SetMinSize(minSize);
SetMaxSize(maxSize);
}
// Called when the project settings change
void TimeToolBar::OnSettingsChanged(wxCommandEvent &evt)
{
evt.Skip(false);
if (evt.GetInt() == ProjectSettings::ChangedProjectRate && mAudioTime)
{
const auto &settings = ProjectSettings::Get(mProject);
mAudioTime->SetSampleRate(settings.GetRate());
}
}
// Called when the format drop downs is changed.
// This causes recreation of the toolbar contents.
void TimeToolBar::OnUpdate(wxCommandEvent &evt)
{
evt.Skip(false);
// Reset to allow resizing to work
SetMinSize(wxDefaultSize);
SetMaxSize(wxDefaultSize);
// Save format name before recreating the controls so they resize properly
if (mListener) {
mListener->TT_SetAudioTimeFormat(mAudioTime->GetBuiltinName(evt.GetInt()));
}
// During initialization, the desired size will have already been set at this point
// and the "best" size" would override it, so we simply send a size event to force
// the content to fit inside the toolbar.
if (mSettingInitialSize) {
mSettingInitialSize = false;
SendSizeEvent();
}
// Otherwise we want the toolbar to resize to fit around the content
else {
// Fit() while retaining height
SetSize(GetBestSize().x, GetSize().y);
}
// Go set the new size limits
SetResizingLimits();
// Inform others the toobar has changed
Updated();
}
void TimeToolBar::OnSize(wxSizeEvent &evt)
{
evt.Skip();
// Can fire before we're ready
if (!mAudioTime) {
return;
}
// Make sure everything is where it's supposed to be
Layout();
// Get the sizer's size and remove any borders the time control might have.
wxSize sizerBR = GetSizer()->GetSize() - (mAudioTime->GetSize() - mAudioTime->GetClientSize());
// Get the content size of the time control. This can be different than the
// control itself due to borders and sizer enduced changes.
wxSize timeBR = mAudioTime->GetDimensions();
// Get the current digit box height
int h = mAudioTime->GetDigitSize().y;
// Increase current size to find the best fit within the new size
if (sizerBR.x >= timeBR.x && sizerBR.y >= timeBR.y) {
do {
h++;
timeBR = ComputeSizing(h);
} while (h < maxDigitH && sizerBR.x >= timeBR.x && sizerBR.y >= timeBR.y);
h--;
}
// In all other cases, we need to decrease current size to fit within new size
else if (sizerBR.x < timeBR.x || sizerBR.y < timeBR.y) {
do {
h--;
timeBR = ComputeSizing(h);
} while (h >= minDigitH && (sizerBR.x < timeBR.x || sizerBR.y < timeBR.y));
}
if (h != mAudioTime->GetDigitSize().y) {
mAudioTime->SetDigitSize(h * mDigitRatio, h);
}
// Redraw the display immediately to smooth out resizing
Update();
}
void TimeToolBar::OnIdle(wxIdleEvent &evt)
{
evt.Skip();
double audioTime;
auto &projectAudioIO = ProjectAudioIO::Get(mProject);
if (projectAudioIO.IsAudioActive()) {
auto gAudioIO = AudioIOBase::Get();
audioTime = gAudioIO->GetStreamTime();
}
else {
const auto &playRegion = ViewInfo::Get(mProject).playRegion;
audioTime = playRegion.GetStart();
}
mAudioTime->SetValue(wxMax(0.0, audioTime));
}
static RegisteredToolbarFactory factory
{
TimeBarID,
[]( AudacityProject &project )
{
return ToolBar::Holder{ safenew TimeToolBar{ project } };
}
};
namespace {
AttachedToolBarMenuItem sAttachment
{
TimeBarID,
wxT("ShowTimeTB"),
/* i18n-hint: Clicking this menu item shows the toolbar
for viewing actual time of the cursor */
XXO("&Time Toolbar"),
{
Registry::OrderingHint::After,
"ShowSelectionTB"
}
};
}