Audacity  2.2.2
SpectralSelectionBar.cpp
Go to the documentation of this file.
1 /**********************************************************************
2 
3 Audacity: A Digital Audio Editor
4 
5 SpectralSelectionBar.cpp
6 
7 Copyright 2014 Dominic Mazzoni
8 
9 This program is free software; you can redistribute it and/or modify
10 it under the terms of the GNU General Public License as published by
11 the Free Software Foundation; either version 2 of the License, or
12 (at your option) any later version.
13 
14 *******************************************************************//****************************************************************//*******************************************************************/
27 
28 
29 #include "../Audacity.h"
30 
31 #include <algorithm>
32 #include "../MemoryX.h"
33 
34 // For compilers that support precompilation, includes "wx/wx.h".
35 #include <wx/wxprec.h>
36 
37 #ifndef WX_PRECOMP
38 #include <wx/defs.h>
39 #include <wx/button.h>
40 #include <wx/checkbox.h>
41 #include <wx/combobox.h>
42 #include <wx/intl.h>
43 #include <wx/radiobut.h>
44 #include <wx/settings.h>
45 #include <wx/sizer.h>
46 #include <wx/valtext.h>
47 #include <wx/window.h>
48 #endif
49 #include <wx/statline.h>
50 
52 #include "SpectralSelectionBar.h"
53 
54 #include "../Prefs.h"
55 #include "../AllThemeResources.h"
56 #include "../SelectedRegion.h"
57 #include "../widgets/NumericTextCtrl.h"
58 
59 #include "../Experimental.h"
60 #include "../Internat.h"
61 
62 #if wxUSE_ACCESSIBILITY
63 #include "../widgets/WindowAccessible.h"
64 #endif
65 
66 #ifdef EXPERIMENTAL_SPECTRAL_EDITING
67 
69 
70 enum {
77 };
78 
79 BEGIN_EVENT_TABLE(SpectralSelectionBar, ToolBar)
80  EVT_SIZE(SpectralSelectionBar::OnSize)
81  EVT_TEXT(OnCenterID, SpectralSelectionBar::OnCtrl)
82  EVT_TEXT(OnWidthID, SpectralSelectionBar::OnCtrl)
83  EVT_TEXT(OnLowID, SpectralSelectionBar::OnCtrl)
84  EVT_TEXT(OnHighID, SpectralSelectionBar::OnCtrl)
85  EVT_CHOICE(OnChoiceID, SpectralSelectionBar::OnChoice)
86  EVT_COMMAND(wxID_ANY, EVT_FREQUENCYTEXTCTRL_UPDATED, SpectralSelectionBar::OnUpdate)
87  EVT_COMMAND(wxID_ANY, EVT_BANDWIDTHTEXTCTRL_UPDATED, SpectralSelectionBar::OnUpdate)
89 
90 static const wxString preferencePath
91 (wxT("/GUI/Toolbars/SpectralSelection/CenterAndWidthChoice"));
92 
94 : ToolBar(SpectralSelectionBarID, _("Spectral Selection"), wxT("SpectralSelection"))
95 , mListener(NULL), mbCenterAndWidth(true)
96 , mCenter(0.0), mWidth(0.0), mLow(0.0), mHigh(0.0)
97 , mCenterCtrl(NULL), mWidthCtrl(NULL), mLowCtrl(NULL), mHighCtrl(NULL)
98 , mChoice(NULL)
99 {
100 }
101 
103 {
104  // Do nothing, sizer deletes the controls
105 }
106 
107 void SpectralSelectionBar::Create(wxWindow * parent)
108 {
109  ToolBar::Create(parent);
110  mHeight = wxWindowBase::GetSizer()->GetSize().GetHeight();
111 }
112 
114 {
115  SetBackgroundColour( theTheme.Colour( clrMedium ) );
116  gPrefs->Read(preferencePath, &mbCenterAndWidth, true);
117 
118  // This will be inherited by all children:
119  SetFont(wxFont(
120 #ifdef __WXMAC__
121  12
122 #else
123  9
124 #endif
125  ,
126  wxFONTFAMILY_SWISS, wxFONTSTYLE_NORMAL, wxFONTWEIGHT_NORMAL));
127 
128  /* we don't actually need a control yet, but we want to use its methods
129  * to do some look-ups, so we'll have to create one. We can't make the
130  * look-ups static because they depend on translations which are done at
131  * runtime */
132 
133  auto frequencyFormatName = mListener
135  : NumericFormatId{};
136  auto bandwidthFormatName = mListener
138  : NumericFormatId{};
139 
140  wxFlexGridSizer *mainSizer;
141  Add((mainSizer = safenew wxFlexGridSizer(1, 1, 1)), 0,wxALIGN_TOP | wxLEFT | wxTOP, 5);
142 
143  //
144  // Top row, choice box
145  //
146 
147  const wxString choices[2] = {
148  _("Center frequency and Width"),
149  _("Low and High Frequencies"),
150  };
151  mChoice = safenew wxChoice
152  (this, OnChoiceID, wxDefaultPosition, wxDefaultSize, 2, choices,
153  0, wxDefaultValidator, _("Spectral Selection"));
154  mChoice->SetSelection(mbCenterAndWidth ? 0 : 1);
155 #if wxUSE_ACCESSIBILITY
156  // so that name can be set on a standard control
157  mChoice->SetAccessible(safenew WindowAccessible(mChoice));
158 #endif
159 #ifdef __WXGTK__
160  // Combo boxes are taller on Linux, and if we don't do the following, the selection toolbar will
161  // be three units high.
162  wxSize sz = mChoice->GetBestSize();
163  sz.SetHeight( sz.y-4);
164  mChoice->SetMinSize( sz );
165 #endif
166 
167  mainSizer->Add(mChoice, 0, wxALIGN_TOP | wxEXPAND |wxRIGHT, 6);
168 
169  //
170  // Bottom row, split into two columns, each with one control
171  //
172 
173  {
174  auto subSizer = std::make_unique<wxBoxSizer>(wxHORIZONTAL);
175 
177  this, OnCenterID,
178  NumericConverter::FREQUENCY, frequencyFormatName, 0.0, 44100.0,
181  );
182  mCenterCtrl->SetName(_("Center Frequency"));
183  subSizer->Add(mCenterCtrl, 0, wxALIGN_CENTER_VERTICAL | wxRIGHT, 5);
184 
186  this, OnWidthID,
187  NumericConverter::BANDWIDTH, bandwidthFormatName, 0.0, 44100.0,
189  .InvalidValue( true, -1.0 )
190  );
191  mWidthCtrl->SetName(wxString(_("Bandwidth")));
192  subSizer->Add(mWidthCtrl, 0, wxALIGN_CENTER_VERTICAL | wxRIGHT, 5);
193 
195  this, OnLowID,
196  NumericConverter::FREQUENCY, frequencyFormatName, 0.0, 44100.0,
199  );
200  mLowCtrl->SetName(_("Low Frequency"));
201  subSizer->Add(mLowCtrl, 0, wxALIGN_CENTER_VERTICAL | wxRIGHT, 5);
202 
204  this, OnHighID,
205  NumericConverter::FREQUENCY, frequencyFormatName, 0.0, 44100.0,
208  );
209  mHighCtrl->SetName(wxString(_("High Frequency")));
210  subSizer->Add(mHighCtrl, 0, wxALIGN_CENTER_VERTICAL | wxRIGHT, 5);
211 
212  mCenterCtrl->Show(mbCenterAndWidth);
214  mLowCtrl->Show(!mbCenterAndWidth);
215  mHighCtrl->Show(!mbCenterAndWidth);
216 
217  mainSizer->Add(subSizer.release(), 0, wxALIGN_CENTER_VERTICAL, 0);
218  }
219 
220  mainSizer->Layout();
221 
222  Layout();
223 
224  SetMinSize(GetSizer()->GetMinSize());
225 }
226 
228 {
229  {
230  wxCommandEvent e(EVT_FREQUENCYTEXTCTRL_UPDATED);
231  e.SetInt((mbCenterAndWidth? mCenterCtrl : mLowCtrl)->GetFormatIndex());
232  OnUpdate(e);
233  }
234 
235  if (mbCenterAndWidth)
236  {
237  wxCommandEvent e(EVT_BANDWIDTHTEXTCTRL_UPDATED);
238  e.SetInt(mWidthCtrl->GetFormatIndex());
239  OnUpdate(e);
240  }
241 
242  // Set label to pull in language change
243  SetLabel(_("Spectral Selection"));
244 
246 
247  // Give base class a chance
249 }
250 
252 {
253  mListener = l;
256 };
257 
258 void SpectralSelectionBar::OnSize(wxSizeEvent &evt)
259 {
260  Refresh(true);
261 
262  evt.Skip();
263 }
264 
266 {
267  const double nyq = mListener->SSBL_GetRate() / 2.0;
268 
269  double bottom, top;
270  if (mbCenterAndWidth) {
273  if ((mCenter < 0 || mWidth < 0) &&
274  (mLow >= 0 || mHigh >= 0))
275  // Transition from defined spectral selection to undefined
276  bottom = top = SelectedRegion::UndefinedFrequency;
277  else if (mCenter < 0 && mWidth < 0)
278  bottom = top = SelectedRegion::UndefinedFrequency;
279  else {
280  if (mCenter < 0) {
281  mWidth = log(std::min(nyq, exp(mWidth)));
282  // Choose arbitrary center for the width
283  mCenter = sqrt(nyq);
284  }
285  else if (mWidth < 0) {
286  mCenter = std::max(1.0, std::min(nyq, mCenter));
287  // Choose arbitrary width for the center
288  const double ratio = std::min(mCenter, nyq / mCenter);
289  mWidth = log(ratio * ratio);
290  }
291  else {
292  mCenter = std::max(1.0, std::min(nyq, mCenter));
293  double ratio = std::min(mCenter, nyq / mCenter);
294  mWidth = std::min(2 * log(ratio), mWidth);
295  }
296 
297  const double ratio = exp(mWidth / 2);
298  bottom = mCenter / ratio, top = mCenter * ratio;
299  }
300  }
301  else {
302  bottom = mLowCtrl->GetValue();
303  top = mHighCtrl->GetValue();
304 
305  if (bottom >= 0)
306  bottom = std::min(nyq, bottom);
307  else
309 
310  if (top >= 0)
311  top = std::min(nyq, top);
312  else
314  // These have to be in the right order.
315  if( bottom > top ){
316  // Oops. We must fix the order.
317  if( mLowCtrl->HasFocus() )
318  top = bottom;
319  else
320  bottom = top;
321  }
322  }
323 
324 
325  mLow = bottom;
326  mHigh = top;
327  //SetBounds();
328 
329  // Notify project and track panel, which may change
330  // the values again, and call back to us in SetFrequencies()
331  mListener->SSBL_ModifySpectralSelection(bottom, top, done);
332 }
333 
334 void SpectralSelectionBar::OnCtrl(wxCommandEvent & event)
335 {
336  ModifySpectralSelection(event.GetInt() != 0);
337 }
338 
339 void SpectralSelectionBar::OnChoice(wxCommandEvent &)
340 {
341  mbCenterAndWidth = (0 == mChoice->GetSelection());
343  gPrefs->Flush();
344 
347  mLowCtrl->Show(!mbCenterAndWidth);
348  mHighCtrl->Show(!mbCenterAndWidth);
349 
351  GetSizer()->Layout(); // Required so that the layout does not mess up on Windows when changing the format.
352  wxWindowBase::GetSizer()->SetMinSize(wxSize(0, mHeight)); // so that height of toolbar does not change
353  wxWindowBase::GetSizer()->SetSizeHints(this);
354  Updated();
355 }
356 
357 void SpectralSelectionBar::OnUpdate(wxCommandEvent &evt)
358 {
359  int index = evt.GetInt();
360  wxWindow *w = FindFocus();
361  bool centerFocus = (w && w == mCenterCtrl);
362  bool widthFocus = (w && w == mWidthCtrl);
363  bool lowFocus = (w && w == mLowCtrl);
364  bool highFocus = (w && w == mHighCtrl);
365 
366  evt.Skip(false);
367 
368  // Save formats before recreating the controls so they resize properly
369  wxEventType type = evt.GetEventType();
370  if (type == EVT_FREQUENCYTEXTCTRL_UPDATED) {
371  NumericTextCtrl *frequencyCtrl = (mbCenterAndWidth ? mCenterCtrl : mLowCtrl);
372  auto frequencyFormatName = frequencyCtrl->GetBuiltinName(index);
373  mListener->SSBL_SetFrequencySelectionFormatName(frequencyFormatName);
374  }
375  else if (mbCenterAndWidth &&
376  type == EVT_BANDWIDTHTEXTCTRL_UPDATED) {
377  auto bandwidthFormatName = mWidthCtrl->GetBuiltinName(index);
378  mListener->SSBL_SetBandwidthSelectionFormatName(bandwidthFormatName);
379  }
380 
381  // ToolBar::ReCreateButtons() will get rid of our sizers and controls
382  // so reset pointers first.
383  mCenterCtrl = mWidthCtrl = NULL;
384  mLowCtrl = mHighCtrl = NULL;
385 
388 
389 
390  if (centerFocus) {
391  mCenterCtrl->SetFocus();
392  }
393  else if (widthFocus) {
394  mWidthCtrl->SetFocus();
395  }
396  else if (lowFocus) {
397  mLowCtrl->SetFocus();
398  }
399  else if (highFocus) {
400  mHighCtrl->SetFocus();
401  }
402 
403  Updated();
404 }
405 
407 {
408  if (mbCenterAndWidth) {
411  }
412  else {
413  //Bug 1633
414  //The controls may not be able to show mHigh, e.g.
415  //if set to Hz, and in that case we should either show invalid
416  //or 'do the best we can' and truncate.
417  //If we set bounds we instead clip to the mHigh to mLow,
418  //So no SetBounds, for now.
419  //SetBounds();
422  }
423 }
424 
426 {
427  if (mHigh >= 0)
429  else
431 
432  if (mLow >= 0)
434  else
436 }
437 
438 void SpectralSelectionBar::SetFrequencies(double bottom, double top)
439 {
440  mLow = bottom;
441  mHigh = top;
442 
443  if (bottom > 0 && top >= bottom)
444  mWidth = log(top / bottom), mCenter = sqrt(top * bottom);
445  else
446  mWidth = mCenter = -1.0;
447 
449 }
450 
452 {
453  NumericTextCtrl *frequencyCtrl = (mbCenterAndWidth ? mCenterCtrl : mLowCtrl);
454  frequencyCtrl->SetFormatName(formatName);
455 
456  wxCommandEvent e(EVT_FREQUENCYTEXTCTRL_UPDATED);
457  e.SetInt(frequencyCtrl->GetFormatIndex());
458  OnUpdate(e);
459 }
460 
462 {
463  if (mbCenterAndWidth) {
464  mWidthCtrl->SetFormatName(formatName);
465 
466  wxCommandEvent e(EVT_BANDWIDTHTEXTCTRL_UPDATED);
467  e.SetInt(mWidthCtrl->GetFormatIndex());
468  OnUpdate(e);
469  }
470 }
471 
472 #endif // #ifdef EXPERIMENTAL_SPECTRAL_EDITING
AudacityPrefs * gPrefs
Definition: Prefs.cpp:73
AUDACITY_DLL_API Theme theTheme
Definition: Theme.cpp:209
Options & InvalidValue(bool has, double value=-1.0)
EVT_COMMAND(wxID_ANY, EVT_FREQUENCYTEXTCTRL_UPDATED, LabelDialog::OnFreqUpdate) LabelDialog
Definition: LabelDialog.cpp:89
virtual void UpdatePrefs()
Definition: ToolBar.cpp:535
virtual double SSBL_GetRate() const =0
virtual void SSBL_SetBandwidthSelectionFormatName(const NumericFormatId &formatName)=0
virtual void SSBL_ModifySpectralSelection(double &bottom, double &top, bool done)=0
void SetLabel(const wxString &label) override
Definition: ToolBar.cpp:374
wxBoxSizer * GetSizer()
Definition: ToolBar.cpp:603
virtual void ReCreateButtons()
Definition: ToolBar.cpp:459
void SetListener(SpectralSelectionBarListener *l)
void OnCtrl(wxCommandEvent &evt)
static const wxString preferencePath(wxT("/GUI/Toolbars/SpectralSelection/CenterAndWidthChoice"))
NumericTextCtrl * mCenterCtrl
NumericTextCtrl * mHighCtrl
#define safenew
Definition: Audacity.h:230
void SetMaxValue(double maxValue)
virtual const NumericFormatId & SSBL_GetFrequencySelectionFormatName()=0
NumericTextCtrl * mWidthCtrl
An alternative to using wxWindowAccessible, which in wxWidgets 3.1.1 contained GetParent() which was ...
void SetBandwidthSelectionFormatName(const NumericFormatId &formatName)
virtual void SSBL_SetFrequencySelectionFormatName(const NumericFormatId &formatName)=0
(not quite a Toolbar) at foot of screen for setting and viewing the frequency selection range...
virtual const NumericFormatId & SSBL_GetBandwidthSelectionFormatName()=0
void Add(wxWindow *window, int proportion=0, int flag=wxALIGN_TOP, int border=0, wxObject *userData=NULL)
Definition: ToolBar.cpp:611
virtual void Create(wxWindow *parent)
Definition: ToolBar.cpp:438
int min(int a, int b)
IdentInterfaceSymbol pairs a persistent string identifier used internally with an optional...
void SetFrequencies(double bottom, double top)
void SetValue(double newValue)
void OnUpdate(wxCommandEvent &evt)
void Updated()
Definition: ToolBar.cpp:592
void SetMinValue(double minValue)
void SetFormatName(const NumericFormatId &formatName)
void RegenerateTooltips() override
_("Move Track &Down")+wxT("\t")+(GetActiveProject() -> GetCommandManager() ->GetKeyFromName(wxT("TrackMoveDown")).Raw()), OnMoveTrack) POPUP_MENU_ITEM(OnMoveTopID, _("Move Track to &Top")+wxT("\t")+(GetActiveProject() ->GetCommandManager() ->GetKeyFromName(wxT("TrackMoveTop")).Raw()), OnMoveTrack) POPUP_MENU_ITEM(OnMoveBottomID, _("Move Track to &Bottom")+wxT("\t")+(GetActiveProject() ->GetCommandManager() ->GetKeyFromName(wxT("TrackMoveBottom")).Raw()), OnMoveTrack)#define SET_TRACK_NAME_PLUGIN_SYMBOLclass SetTrackNameCommand:public AudacityCommand
void SetFrequencySelectionFormatName(const NumericFormatId &formatName)
NumericFormatId GetBuiltinName(const int index)
bool Layout() override
void Create(wxWindow *parent) override
NumericTextCtrl * mLowCtrl
wxColour & Colour(int iIndex)
Definition: Theme.cpp:1225
A class used to forward events to do with changes in the SpectralSelectionBar.
END_EVENT_TABLE()
void ModifySpectralSelection(bool done=false)
void OnChoice(wxCommandEvent &evt)
void OnSize(wxSizeEvent &evt)
static const int UndefinedFrequency
IMPLEMENT_CLASS(SpectralSelectionBar, ToolBar)
Works with ToolManager and ToolDock to provide a dockable window in which buttons can be placed...
Definition: ToolBar.h:87
SpectralSelectionBarListener * mListener