Audacity  3.0.3
LabelDialog.cpp
Go to the documentation of this file.
1 /**********************************************************************
2 
3  Audacity: A Digital Audio Editor
4 
5  LabelDialog.cpp
6 
7  Dominic Mazzoni
8 
9 *******************************************************************//*******************************************************************/
15 
16 
17 #include "LabelDialog.h"
18 
19 #include <wx/button.h>
20 #include <wx/defs.h>
21 #include <wx/choice.h>
22 #include <wx/dc.h>
23 #include <wx/dialog.h>
24 #include <wx/grid.h>
25 #include <wx/intl.h>
26 #include <wx/scrolbar.h>
27 #include <wx/settings.h>
28 #include <wx/sizer.h>
29 #include <wx/stattext.h>
30 #include <wx/textdlg.h>
31 
32 #include "ShuttleGui.h"
33 #include "LabelTrack.h"
34 #include "Prefs.h"
35 #include "Project.h"
36 #include "ProjectWindow.h"
37 #include "ViewInfo.h"
41 #include "widgets/Grid.h"
42 #include "widgets/HelpSystem.h"
43 
44 #include "FileNames.h"
45 #include <limits>
46 
47 enum Column
48 {
55  Col_Max
56 };
57 
58 
59 
60 class RowData
61 {
62  public:
63  RowData(int index_, const wxString &title_, const SelectedRegion &selectedRegion_)
64  : index(index_), title(title_), selectedRegion(selectedRegion_)
65  {}
66 
67  int index;
68  wxString title;
70 };
71 
72 enum {
73  ID_INSERTA = 11000,
77  ID_EXPORT
78 };
79 
80 BEGIN_EVENT_TABLE(LabelDialog, wxDialogWrapper)
81  EVT_GRID_SELECT_CELL(LabelDialog::OnSelectCell)
82  EVT_GRID_CELL_CHANGED(LabelDialog::OnCellChange)
89  EVT_BUTTON(wxID_CANCEL, LabelDialog::OnCancel)
90  EVT_COMMAND(wxID_ANY, EVT_TIMETEXTCTRL_UPDATED, LabelDialog::OnUpdate)
91  EVT_COMMAND(wxID_ANY, EVT_FREQUENCYTEXTCTRL_UPDATED,
92  LabelDialog::OnFreqUpdate)
93  EVT_BUTTON(wxID_HELP, LabelDialog::OnHelp)
95 
96 LabelDialog::LabelDialog(wxWindow *parent,
97  AudacityProject &project,
98  TrackList *tracks,
99  LabelTrack *selectedTrack,
100  int index,
101  ViewInfo &viewinfo,
102  double rate,
103  const NumericFormatSymbol & format,
104  const NumericFormatSymbol &freqFormat)
105 : wxDialogWrapper(parent,
106  wxID_ANY,
107  XO("Edit Labels"),
108  wxDefaultPosition,
109  wxSize(800, 600),
110  wxDEFAULT_DIALOG_STYLE | wxRESIZE_BORDER)
111  , mProject{ project }
112  , mTracks(tracks)
113  , mSelectedTrack(selectedTrack)
114  , mIndex(index)
115  , mViewInfo(&viewinfo),
116  mRate(rate),
117  mFormat(format)
118  , mFreqFormat(freqFormat)
119 {
120  SetName();
121  Populate();
122 }
123 
125 {
126 }
127 
129 {
130  // Build the initial (empty) grid
131  mGrid->CreateGrid(0, Col_Max, wxGrid::wxGridSelectRows);
132  mGrid->SetDefaultCellAlignment(wxALIGN_LEFT, wxALIGN_CENTER);
133  mGrid->SetRowLabelSize(0);
134 
135  size_t ii = 0;
136  for ( const auto &label : {
137  /* i18n-hint: (noun). A track contains waves, audio etc.*/
138  XO("Track"),
139  /* i18n-hint: (noun)*/
140  XO("Label"),
141  /* i18n-hint: (noun) of a label*/
142  XO("Start Time"),
143  /* i18n-hint: (noun) of a label*/
144  XO("End Time"),
145  /* i18n-hint: (noun) of a label*/
146  XO("Low Frequency"),
147  /* i18n-hint: (noun) of a label*/
148  XO("High Frequency"),
149  })
150  mGrid->SetColLabelValue( ii++, label.Translation() );
151 
152  // Create and remember editors. No need to DELETE these as the wxGrid will
153  // do it for us. (The DecRef() that is needed after GetDefaultEditorForType
154  // becomes the duty of the wxGridCellAttr objects after we set them in the grid.)
155  mChoiceEditor = (ChoiceEditor *) mGrid->GetDefaultEditorForType(GRID_VALUE_CHOICE);
156  mTimeEditor = static_cast<NumericEditor*>
157  (mGrid->GetDefaultEditorForType(GRID_VALUE_TIME));
158  mFrequencyEditor = static_cast<NumericEditor *>
159  (mGrid->GetDefaultEditorForType(GRID_VALUE_FREQUENCY));
160 
161  // Initialize and set the track name column attributes
162  wxGridCellAttr *attr;
163  mGrid->SetColAttr(Col_Track, (attr = safenew wxGridCellAttr));
164  attr->SetEditor(mChoiceEditor);
165  mTrackNames.push_back(_("New..."));
166 
167  // Initialize and set the time column attributes
168  mGrid->SetColAttr(Col_Stime, (attr = safenew wxGridCellAttr));
169  // Don't need DecRef() after this GetDefaultRendererForType.
170  attr->SetRenderer(mGrid->GetDefaultRendererForType(GRID_VALUE_TIME));
171  attr->SetEditor(mTimeEditor);
172  attr->SetAlignment(wxALIGN_CENTER, wxALIGN_CENTER);
173 
174  mGrid->SetColAttr(Col_Etime, attr->Clone());
175 
176  // Initialize and set the frequency column attributes
177  mGrid->SetColAttr(Col_Lfreq, (attr = safenew wxGridCellAttr));
178  // Don't need DecRef() after this GetDefaultRendererForType.
179  attr->SetRenderer(mGrid->GetDefaultRendererForType(GRID_VALUE_FREQUENCY));
180  attr->SetEditor(mFrequencyEditor);
181  attr->SetAlignment(wxALIGN_CENTER, wxALIGN_CENTER);
182 
183  mGrid->SetColAttr(Col_Hfreq, attr->Clone());
184 
185  // Seems there's a bug in wxGrid. Adding only 1 row does not
186  // allow SetCellSize() to work properly and you will not get
187  // the expected 1 row by 4 column cell.
188  //
189  // So, we set the minimum row height to 0 and basically hide
190  // the extra row by setting its height to 0. And not allowing the
191  // rows to be manually resized prevents the user from ever seeing
192  // the extra row.
193  mGrid->SetRowMinimalAcceptableHeight(0);
194  mGrid->EnableDragRowSize(false);
195 
196  // Locate all labels in current track list
197  FindAllLabels();
198 
199  // Populate the grid
201 
202  // Resize the label name column and ensure it doesn't go below an
203  // arbitrary width.
204  //
205  // This should not be in TransferDataToWindow() since a user might
206  // resize the column and we'd resize it back to the minimum.
207  mGrid->AutoSizeColumn(Col_Label, false );
208  mGrid->SetColSize(Col_Label, wxMax(150, mGrid->GetColSize(Col_Label)));
209  mGrid->SetColMinimalWidth(Col_Label, mGrid->GetColSize(Col_Label));
210 
211 }
212 
213 
216 {
217 
218  //------------------------- Main section --------------------
219  ShuttleGui S(this, eIsCreating);
221  // ----------------------- End of main section --------------
222 
223  // Go populate the macros list.
224  PopulateLabels();
225 
226  // Layout the works
227  Layout();
228  //Fit();
229 
230  // Resize width based on width of columns and the vertical scrollbar
231  wxRect r = mGrid->GetGridColLabelWindow()->GetRect();
232  wxScrollBar sb(this, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxSB_VERTICAL);
233  r.width += sb.GetSize().GetWidth() + 6;
234 
235  // Add the size of the right column of buttons too...
236  wxWindow * w = FindWindowById( ID_IMPORT, this );
237  wxASSERT( w );
238  if( w )
239  r.width += w->GetSize().GetWidth();
240 
241  SetClientSize(r.width, 300);
242 
243  // Make sure it doesn't go below this size
244  r = GetRect();
245  SetSizeHints(r.GetWidth(), r.GetHeight());
246 
247  // Bug 1465
248  // There might be a saved size, in which case use that.
249  ReadSize();
250 
251  // Center on display
252  Center();
253 }
254 
256 {
257  S.AddFixedText(XO("Press F2 or double click to edit cell contents."));
258  S.StartHorizontalLay(wxEXPAND,1);
259  {
260  S.StartVerticalLay(wxEXPAND,1);
261  {
262  mGrid = safenew Grid(S.GetParent(), wxID_ANY);
263  S.Prop(1).AddWindow( mGrid );
264  }
265  S.EndVerticalLay();
266  S.StartVerticalLay(0);
267  {
268  //S.Id(ID_INSERTA).AddButton(XO("&Insert"), wxALIGN_LEFT);
269  S.Id(ID_INSERTB).AddButton(XXO("&Insert"), wxALIGN_LEFT);
270  //S.Id(EditButtonID).AddButton(XO("&Edit"), wxALIGN_LEFT);
271  S.Id(ID_REMOVE).AddButton(XXO("De&lete"), wxALIGN_LEFT);
272  S.Id(ID_IMPORT).AddButton(XXO("I&mport..."), wxALIGN_LEFT);
273  S.Id(ID_EXPORT).AddButton(XXO("&Export..."), wxALIGN_LEFT);
274  }
275  S.EndVerticalLay();
276  }
277  S.EndHorizontalLay();
278 
279  S.StartHorizontalLay(wxALIGN_RIGHT, false);
280  {
282  }
283  S.EndHorizontalLay();
284 }
285 
286 void LabelDialog::OnHelp(wxCommandEvent & WXUNUSED(event))
287 {
288  const auto &page = GetHelpPageName();
289  HelpSystem::ShowHelp(this, page, true);
290 }
291 
292 
294 {
295  int cnt = mData.size();
296  int i;
297 
298  // Set the editor parameters. Do this each time since they may change
299  // due to NEW tracks and change in NumericTextCtrl format. Rate won't
300  // change but might as well leave it here.
306 
307  // Disable redrawing until we're done
308  mGrid->BeginBatch();
309 
310  // Delete all rows
311  if (mGrid->GetNumberRows()) {
312  mGrid->DeleteRows(0, mGrid->GetNumberRows());
313  }
314 
315  // Add the exact number that we'll need
316  mGrid->InsertRows(0, cnt);
317 
318  // Populate the rows
319  for (i = 0; i < cnt; i++) {
320  RowData &rd = mData[i];
321 
322  // Set the cell contents
323  mGrid->SetCellValue(i, Col_Track, TrackName(rd.index));
324  mGrid->SetCellValue(i, Col_Label, rd.title);
325  mGrid->SetCellValue(i, Col_Stime,
326  wxString::Format(wxT("%g"), rd.selectedRegion.t0()));
327  mGrid->SetCellValue(i, Col_Etime,
328  wxString::Format(wxT("%g"), rd.selectedRegion.t1()));
329  mGrid->SetCellValue(i, Col_Lfreq,
330  wxString::Format(wxT("%g"), rd.selectedRegion.f0()));
331  mGrid->SetCellValue(i, Col_Hfreq,
332  wxString::Format(wxT("%g"), rd.selectedRegion.f1()));
333  }
334 
335  // Autosize all the rows
336  mGrid->AutoSizeRows(true);
337 
338  // Resize the track name column. Use a wxChoice to determine the maximum
339  // width needed.
340  wxChoice tc(this, wxID_ANY, wxDefaultPosition, wxDefaultSize, mTrackNames);
341  mGrid->SetColSize(Col_Track, tc.GetSize().x);
342  mGrid->SetColMinimalWidth(Col_Track, tc.GetSize().x);
343 
344  // Autosize the time columns and set their minimal widths
345  mGrid->AutoSizeColumn(Col_Stime);
346  mGrid->AutoSizeColumn(Col_Etime);
347  mGrid->AutoSizeColumn(Col_Lfreq);
348  mGrid->AutoSizeColumn(Col_Hfreq);
349 
350  // We're done, so allow the grid to redraw
351  mGrid->EndBatch();
352 
353  return true;
354 }
355 
356 bool LabelDialog::Show(bool show)
357 {
358  bool ret = wxDialogWrapper::Show(show);
359 
360 #if defined(__WXMAC__) || defined(__WXGTK__)
361  if (show) {
362  mGrid->SetFocus(); // Required for Linux and Mac.
363  }
364 #endif
365 
366  // Set initial row
367  // (This will not work until the grid is actually displayed)
368  if (show && mInitialRow != -1) {
369  mGrid->GoToCell(mInitialRow, Col_Label);
370  }
371 
372  return ret;
373 }
374 
376 {
377  int cnt = mData.size();
378  int i;
379  int tndx = 0;
380 
381  // Clear label tracks of labels
382  for (auto lt : mTracks->Any<LabelTrack>()) {
383  ++tndx;
384  if (!mSelectedTrack) {
385  for (i = lt->GetNumLabels() - 1; i >= 0 ; i--) {
386  lt->DeleteLabel(i);
387  }
388  }
389  else if (mSelectedTrack == lt && mIndex > -1) {
390  lt->DeleteLabel(mIndex);
391  }
392  else
393  // Do nothing to the nonselected tracks
394  ;
395  }
396 
397  // Create any added tracks
398  while (tndx < (int)mTrackNames.size() - 1) {
399 
400  // Extract the name
401  wxString name = mTrackNames[tndx + 1].AfterFirst(wxT('-')).Mid(1);
402 
403  // Create the NEW track and add to track list
404  auto newTrack = std::make_shared<LabelTrack>();
405  newTrack->SetName(name);
406  mTracks->Add( newTrack );
407  tndx++;
408  }
409 
410  // Repopulate with updated labels
411  for (i = 0; i < cnt; i++) {
412  RowData &rd = mData[i];
413 
414  // Look for track with matching index
415  tndx = 1;
416  LabelTrack *lt{};
417  for (auto t : mTracks->Any<LabelTrack>()) {
418  lt = t;
419  if (rd.index == tndx++) {
420  break;
421  }
422  }
423  wxASSERT(lt);
424  if (!lt)
425  return false;
426 
427  // Add the label to it
428  lt->AddLabel(rd.selectedRegion, rd.title);
430  }
431 
432  return true;
433 }
434 
436 {
437  if (mGrid->IsCellEditControlShown()) {
438  mGrid->HideCellEditControl();
439  mGrid->SaveEditControlValue();
440  }
441 
442  return true;
443 }
444 
445 wxString LabelDialog::TrackName(int & index, const wxString &dflt)
446 {
447  // Generate a NEW track name if the passed index is out of range
448  if (index < 1 || index >= (int)mTrackNames.size()) {
449  index = mTrackNames.size();
450  mTrackNames.push_back(wxString::Format(wxT("%d - %s"), index, dflt));
451  }
452 
453  // Return the track name
454  return mTrackNames[index];
455 }
456 
458 {
459  // Add labels from all label tracks
460  for (auto lt : mTracks->Any<const LabelTrack>()) {
461  AddLabels(lt);
462  }
463 
464  FindInitialRow();
465 
466  if (mData.size() == 0) {
467  wxCommandEvent e;
468  OnInsert(e);
469  }
470 }
471 
473 {
474  wxString lab;
475  int tndx = 0;
476  int i;
477 
478  // Add a NEW track name
479  TrackName(tndx, t->GetName());
480 
481  // If editor was invoked for one label, add that one only, else add all.
482  if (!mSelectedTrack || mSelectedTrack == t) {
483  for (i = 0; i < t->GetNumLabels(); i++) {
484  const LabelStruct *ls = t->GetLabel(i);
485 
486  if (mIndex < 0 || mIndex == i)
487  mData.push_back(RowData(tndx, ls->title, ls->selectedRegion));
488  }
489  }
490 }
491 
493 {
494  int cnt = mData.size();
495  mInitialRow = -1;
496 
497  if (cnt == 0)
498  return;
499 
500  // find closest previous label
501 
502  double distMin = std::numeric_limits<double>::max();
503  double dist;
504  double t0 = mViewInfo->selectedRegion.t0();
505  int i;
506  for (i = 0; i < cnt; i++)
507  {
508  dist = t0 - mData[i].selectedRegion.t0();
509  if (dist >= 0.0 && dist < distMin)
510  {
511  mInitialRow = i;
512  distMin = dist;
513  }
514  }
515 
516  // if no previous label was found, find first label
517 
518  if (mInitialRow == -1)
519  {
520  double t0Min = std::numeric_limits<double>::max();
521  for (i = 0; i < cnt; i++)
522  {
523  if (mData[i].selectedRegion.t0() < t0Min)
524  {
525  mInitialRow = i;
526  t0Min = mData[i].selectedRegion.t0();
527  }
528  }
529  }
530 }
531 
532 void LabelDialog::OnUpdate(wxCommandEvent &event)
533 {
534  // Remember the NEW format and repopulate grid
536  NumericConverter::TIME, event.GetString() );
538 
539  event.Skip(false);
540 }
541 
542 void LabelDialog::OnFreqUpdate(wxCommandEvent &event)
543 {
544  // Remember the NEW format and repopulate grid
546  NumericConverter::FREQUENCY, event.GetString() );
548 
549  event.Skip(false);
550 }
551 
552 void LabelDialog::OnInsert(wxCommandEvent &event)
553 {
554  int cnt = mData.size();
555  int row = 0;
556  int index = 0;
557 
558  // Make sure the edit control isn't active before inserting any rows
559  if (mGrid->IsCellEditControlShown()) {
560  mGrid->HideCellEditControl();
561  }
562 
563  // Attempt to guess which track the label should reside on
564  if (cnt > 0) {
565  row = mGrid->GetGridCursorRow();
566  if (row > 0 && row >= cnt) {
568  .index( mGrid->GetCellValue(row - 1, Col_Track) );
569  }
570  else {
572  .index( mGrid->GetCellValue(row, Col_Track) );
573  }
574  }
575 
576  // Insert NEW label before or after the current row
577  if (event.GetId() == ID_INSERTA && row < cnt) {
578  row++;
579  }
580  mData.insert(mData.begin() + row, RowData(index, wxT(""), SelectedRegion()));
581 
582  // Repopulate the grid
584 
585  // Reposition cursor to NEW row/col and put user into edit mode to
586  // set the label name
587  mGrid->SetGridCursor(row, Col_Label);
588  mGrid->EnableCellEditControl(true);
589  mGrid->ShowCellEditControl();
590 }
591 
592 void LabelDialog::OnRemove(wxCommandEvent & WXUNUSED(event))
593 {
594  int row = mGrid->GetGridCursorRow();
595  int col = mGrid->GetGridCursorCol();
596  int cnt = mData.size();
597 
598  // Don't try to remove if no labels exist
599  if (cnt == 0) {
600  return;
601  }
602 
603  // Make sure the edit control isn't active before removing rows
604  if (mGrid->IsCellEditControlShown()) {
605  mGrid->HideCellEditControl();
606  }
607 
608  // Remove the row
609  //RowData &rd = mData[row];
610  mData.erase(mData.begin() + row);
611 
612  // Repopulate the grid
614 
615  // Reposition the cursor
616  if (row > 0 && row >= --cnt) {
617  row--;
618  }
619  mGrid->SetGridCursor(row, col);
620 
621  // Make sure focus isn't lost
622  if (mData.size() == 0 && wxWindow::FindFocus() == mGrid->GetGridWindow()) {
623  wxWindow *ok = wxWindow::FindWindowById( wxID_OK, this);
624  if (ok) {
625  ok->SetFocus();
626  }
627  }
628 }
629 
630 void LabelDialog::OnImport(wxCommandEvent & WXUNUSED(event))
631 {
632  // Ask user for a filename
633  wxString fileName =
634  FileNames::SelectFile(FileNames::Operation::Open,
635  XO("Select a text file containing labels"),
636  wxEmptyString, // Path
637  wxT(""), // Name
638  wxT("txt"), // Extension
640  wxRESIZE_BORDER, // Flags
641  this); // Parent
642 
643  // They gave us one...
644  if (!fileName.empty()) {
645  wxTextFile f;
646 
647  // Get at the data
648  f.Open(fileName);
649  if (!f.IsOpened()) {
651  XO("Could not open file: %s").Format( fileName ) );
652  }
653  else {
654  // Create a temporary label track and load the labels
655  // into it
656  auto lt = std::make_shared<LabelTrack>();
657  lt->Import(f);
658 
659  // Add the labels to our collection
660  AddLabels(lt.get());
661 
662  // Done with the temporary track
663  }
664 
665  // Repopulate the grid
667  }
668 }
669 
670 void LabelDialog::OnExport(wxCommandEvent & WXUNUSED(event))
671 {
672  int cnt = mData.size();
673 
674  // Silly user (could just disable the button, but that's a hassle ;-))
675  if (cnt == 0) {
676  AudacityMessageBox( XO("No labels to export.") );
677  return;
678  }
679 
680  // Extract the actual name.
681  wxString fName = mTrackNames[mTrackNames.size() - 1].AfterFirst(wxT('-')).Mid(1);
682 
683  fName = FileNames::SelectFile(FileNames::Operation::Export,
684  XO("Export Labels As:"),
685  wxEmptyString,
686  fName,
687  wxT("txt"),
689  wxFD_SAVE | wxFD_OVERWRITE_PROMPT | wxRESIZE_BORDER,
690  this);
691 
692  if (fName.empty())
693  return;
694 
695  // Move existing files out of the way. Otherwise wxTextFile will
696  // append to (rather than replace) the current file.
697 
698  if (wxFileExists(fName)) {
699 #ifdef __WXGTK__
700  wxString safetyFileName = fName + wxT("~");
701 #else
702  wxString safetyFileName = fName + wxT(".bak");
703 #endif
704 
705  if (wxFileExists(safetyFileName))
706  wxRemoveFile(safetyFileName);
707 
708  wxRename(fName, safetyFileName);
709  }
710 
711  wxTextFile f(fName);
712 #ifdef __WXMAC__
713  wxFile{}.Create(fName);
714 #else
715  f.Create();
716 #endif
717  f.Open();
718  if (!f.IsOpened()) {
720  XO("Couldn't write to file: %s").Format( fName ) );
721  return;
722  }
723 
724  // Transfer our collection to a temporary label track
725  auto lt = std::make_shared<LabelTrack>();
726  int i;
727 
728  for (i = 0; i < cnt; i++) {
729  RowData &rd = mData[i];
730 
731  lt->AddLabel(rd.selectedRegion, rd.title);
732  }
733 
734  // Export them and clean
735  lt->Export(f);
736 
737 #ifdef __WXMAC__
738  f.Write(wxTextFileType_Mac);
739 #else
740  f.Write();
741 #endif
742  f.Close();
743 }
744 
745 void LabelDialog::OnSelectCell(wxGridEvent &event)
746 {
747  for (auto t: mTracks->Any())
748  t->SetSelected( true );
749 
750  if (!mData.empty())
751  {
752  RowData &rd = mData[event.GetRow()];
754 
756  }
757 
758  event.Skip();
759 }
760 
761 void LabelDialog::OnCellChange(wxGridEvent &event)
762 {
763  static bool guard = false;
764  int row = event.GetRow();
765 
766  // Guard against recursion which can happen when a change to the "NEW label" row
767  // is made. When InsertRow() is done in TransferDataToWindow(), checks are made
768  // within wxGrid to see if the edit control is active and since it hasn't yet
769  // been marked inactive on the first time through here, we get entered again.
770  // Sort of a double change. I think this is probably a bug in wxGrid.
771  if (guard) {
772  return;
773  }
774  guard = true;
775 
776  // The change was to an existing label, so go process it based
777  // on which column was changed.
778  RowData *rd = &mData[row];
779  switch (event.GetCol())
780  {
781  case Col_Track:
782  OnChangeTrack(event, row, rd);
783  break;
784 
785  case Col_Label:
786  OnChangeLabel(event, row, rd);
787  break;
788 
789  case Col_Stime:
790  OnChangeStime(event, row, rd);
791  break;
792 
793  case Col_Etime:
794  OnChangeEtime(event, row, rd);
795  break;
796 
797  case Col_Lfreq:
798  OnChangeLfreq(event, row, rd);
799  break;
800 
801  case Col_Hfreq:
802  OnChangeHfreq(event, row, rd);
803  break;
804  }
805 
806  // Done...no need for protection anymore
807  guard = false;
808 
809  return;
810 }
811 
812 void LabelDialog::OnChangeTrack(wxGridEvent & WXUNUSED(event), int row, RowData *rd)
813 {
814  wxString val = mGrid->GetCellValue(row, Col_Track);
815 
816  // User selected the "New..." choice so ask for a NEW name
817  if ( make_iterator_range( mTrackNames ).index( val ) == 0 ) {
819  XO("New Label Track"),
820  XO("Enter track name"),
821  /* i18n-hint: (noun) it's the name of a kind of track.*/
822  XO("Label Track").Translation());
823 
824  // User canceled so repopulating the grid will set the track
825  // name to the original value
826  if (d.ShowModal() == wxID_CANCEL) {
828  return;
829  }
830 
831  // Force generation of a NEW track name
832  rd->index = 0;
833  TrackName(rd->index, d.GetValue());
834  }
835  else {
836  // Remember the tracks index
837  rd->index = make_iterator_range( mTrackNames ).index( val );
838  }
839 
840  // Repopulate the grid
842 
843  return;
844 }
845 
846 void LabelDialog::OnChangeLabel(wxGridEvent & WXUNUSED(event), int row, RowData *rd)
847 {
848  // Remember the value...no need to repopulate
849  rd->title = mGrid->GetCellValue(row, Col_Label);
850 
851  return;
852 }
853 
854 void LabelDialog::OnChangeStime(wxGridEvent & WXUNUSED(event), int row, RowData *rd)
855 {
856  // Remember the value...no need to repopulate
857  double t {};
858  mGrid->GetCellValue(row, Col_Stime).ToDouble(&t);
859  rd->selectedRegion.setT0(t, false);
860  mGrid->SetCellValue(row, Col_Etime, wxString::Format(wxT("%g"),
861  rd->selectedRegion.t1()));
862 
863  return;
864 }
865 
866 void LabelDialog::OnChangeEtime(wxGridEvent & WXUNUSED(event), int row, RowData *rd)
867 {
868  // Remember the value...no need to repopulate
869  double t {};
870  mGrid->GetCellValue(row, Col_Etime).ToDouble(&t);
871  rd->selectedRegion.setT1(t, false);
872  mGrid->SetCellValue(row, Col_Stime, wxString::Format(wxT("%g"),
873  rd->selectedRegion.t0()));
874 
875  return;
876 }
877 
878 void LabelDialog::OnChangeLfreq(wxGridEvent & WXUNUSED(event), int row, RowData *rd)
879 {
880  // Remember the value...no need to repopulate
881  double f;
882  mGrid->GetCellValue(row, Col_Lfreq).ToDouble(&f);
883  rd->selectedRegion.setF0(f, false);
884  mGrid->SetCellValue(row, Col_Hfreq, wxString::Format(wxT("%g"),
885  rd->selectedRegion.f1()));
886 
887  return;
888 }
889 
890 void LabelDialog::OnChangeHfreq(wxGridEvent & WXUNUSED(event), int row, RowData *rd)
891 {
892  // Remember the value...no need to repopulate
893  double f;
894  mGrid->GetCellValue(row, Col_Hfreq).ToDouble(&f);
895  rd->selectedRegion.setF1(f, false);
896  mGrid->SetCellValue(row, Col_Lfreq, wxString::Format(wxT("%g"),
897  rd->selectedRegion.f0()));
898 
899  return;
900 }
901 
903  wxSize sz = GetSize();
904  int prefWidth, prefHeight;
905  gPrefs->Read(wxT("/LabelEditor/Width"), &prefWidth, sz.x);
906  gPrefs->Read(wxT("/LabelEditor/Height"), &prefHeight, sz.y);
907 
908  wxRect screenRect(wxGetClientDisplayRect());
909  wxSize prefSize = wxSize(prefWidth, prefHeight);
910  prefSize.DecTo(screenRect.GetSize());
911  SetSize(prefSize);
912 }
913 
915  wxSize sz = GetSize();
916  gPrefs->Write(wxT("/LabelEditor/Width"), sz.x);
917  gPrefs->Write(wxT("/LabelEditor/Height"), sz.y);
918  gPrefs->Flush();
919 }
920 
921 void LabelDialog::OnOK(wxCommandEvent & WXUNUSED(event))
922 {
923  if (mGrid->IsCellEditControlShown()) {
924  mGrid->SaveEditControlValue();
925  mGrid->HideCellEditControl();
926  return;
927  }
928 
929  // Standard handling
930  if (Validate() && TransferDataFromWindow()) {
931  WriteSize();
932  EndModal(wxID_OK);
933  }
934 
935  return;
936 }
937 
938 void LabelDialog::OnCancel(wxCommandEvent & WXUNUSED(event))
939 {
940  if (mGrid->IsCellEditControlShown()) {
941  auto editor = mGrid->GetCellEditor(mGrid->GetGridCursorRow(),
942  mGrid->GetGridCursorCol());
943  editor->Reset();
944  // To avoid memory leak, don't forget DecRef()!
945  editor->DecRef();
946  mGrid->HideCellEditControl();
947  return;
948  }
949 
950  WriteSize();
951  // Standard handling
952  EndModal(wxID_CANCEL);
953 
954  return;
955 }
LabelDialog::mGrid
Grid * mGrid
Definition: LabelDialog.h:98
EVT_BUTTON
EVT_BUTTON(wxID_NO, DependencyDialog::OnNo) EVT_BUTTON(wxID_YES
LabelDialog::OnChangeLfreq
void OnChangeLfreq(wxGridEvent &event, int row, RowData *rd)
Definition: LabelDialog.cpp:878
eIsCreating
@ eIsCreating
Definition: ShuttleGui.h:38
LabelDialog::OnChangeHfreq
void OnChangeHfreq(wxGridEvent &event, int row, RowData *rd)
Definition: LabelDialog.cpp:890
ShuttleGuiBase::StartVerticalLay
void StartVerticalLay(int iProp=1)
Definition: ShuttleGui.cpp:1184
AudacityMessageBox
int AudacityMessageBox(const TranslatableString &message, const TranslatableString &caption=XO("Message"), long style=wxOK|wxCENTRE, wxWindow *parent=NULL, int x=wxDefaultCoord, int y=wxDefaultCoord)
Definition: AudacityMessageBox.h:20
make_iterator_range
IteratorRange< Iterator > make_iterator_range(const Iterator &i1, const Iterator &i2)
Definition: MemoryX.h:549
LabelDialog::OnSelectCell
void OnSelectCell(wxGridEvent &event)
Definition: LabelDialog.cpp:745
LabelDialog
Dialog for editing labels.
Definition: LabelDialog.h:36
Col_Label
@ Col_Label
Definition: LabelDialog.cpp:50
GRID_VALUE_FREQUENCY
#define GRID_VALUE_FREQUENCY
Definition: Grid.h:35
HelpSystem.h
GRID_VALUE_TIME
#define GRID_VALUE_TIME
Definition: Grid.h:34
LabelDialog::PopulateLabels
void PopulateLabels()
Definition: LabelDialog.cpp:128
LabelStruct::title
wxString title
Definition: LabelTrack.h:71
gPrefs
FileConfig * gPrefs
Definition: Prefs.cpp:70
LabelDialog::TrackName
wxString TrackName(int &index, const wxString &dflt=_("Label Track"))
Definition: LabelDialog.cpp:445
LabelDialog::OnChangeLabel
void OnChangeLabel(wxGridEvent &event, int row, RowData *rd)
Definition: LabelDialog.cpp:846
EVT_COMMAND
EVT_COMMAND(wxID_ANY, EVT_FREQUENCYTEXTCTRL_UPDATED, LabelDialog::OnFreqUpdate) LabelDialog
Definition: LabelDialog.cpp:91
SelectedRegion::t1
double t1() const
Definition: SelectedRegion.h:95
eHelpButton
@ eHelpButton
Definition: ShuttleGui.h:604
Track::GetName
wxString GetName() const
Definition: Track.h:410
Project.h
Col_Track
@ Col_Track
Definition: LabelDialog.cpp:49
LabelDialog::mData
RowDataArray mData
Definition: LabelDialog.h:103
LabelDialog::~LabelDialog
~LabelDialog()
Definition: LabelDialog.cpp:124
AudacityTextEntryDialog
Wrap wxTextEntryDialog so that caption IS translatable.
Definition: AudacityTextEntryDialog.h:23
Format
Abstract base class used in importing a file.
TrackList
A flat linked list of tracks supporting Add, Remove, Clear, and Contains, serialization of the list o...
Definition: Track.h:1264
Col_Etime
@ Col_Etime
Definition: LabelDialog.cpp:52
ViewInfo
Definition: ViewInfo.h:173
Grid
Supplies an accessible grid based on wxGrid.
Definition: Grid.h:185
Grid.h
LabelDialog::FindAllLabels
void FindAllLabels()
Definition: LabelDialog.cpp:457
LabelDialog::mViewInfo
ViewInfo * mViewInfo
Definition: LabelDialog.h:108
XO
#define XO(s)
Definition: Internat.h:31
LabelDialog::OnExport
void OnExport(wxCommandEvent &event)
Definition: LabelDialog.cpp:670
LabelDialog::mSelectedTrack
LabelTrack * mSelectedTrack
Definition: LabelDialog.h:106
LabelDialog::OnHelp
void OnHelp(wxCommandEvent &event)
Definition: LabelDialog.cpp:286
TrackList::Add
TrackKind * Add(const std::shared_ptr< TrackKind > &t)
Definition: Track.h:1487
LabelDialog::OnInsert
void OnInsert(wxCommandEvent &event)
Definition: LabelDialog.cpp:552
LabelTrack
A LabelTrack is a Track that holds labels (LabelStruct).
Definition: LabelTrack.h:88
GRID_VALUE_CHOICE
#define GRID_VALUE_CHOICE
Definition: Grid.h:117
Col_Max
@ Col_Max
Definition: LabelDialog.cpp:55
LabelDialog::OnOK
void OnOK(wxCommandEvent &event)
Definition: LabelDialog.cpp:921
ProjectWindow::Get
static ProjectWindow & Get(AudacityProject &project)
Definition: ProjectWindow.cpp:533
ID_REMOVE
@ ID_REMOVE
Definition: LabelDialog.cpp:75
LabelDialog::mFrequencyEditor
NumericEditor * mFrequencyEditor
Definition: LabelDialog.h:101
FileNames::AllFiles
AUDACITY_DLL_API const FileType AllFiles
Definition: FileNames.h:74
LabelDialog::Validate
bool Validate() override
Definition: LabelDialog.cpp:435
Col_Lfreq
@ Col_Lfreq
Definition: LabelDialog.cpp:53
LabelStruct
A LabelStruct holds information for ONE label in a LabelTrack.
Definition: LabelTrack.h:30
HelpSystem::ShowHelp
static void ShowHelp(wxWindow *parent, const FilePath &localFileName, const URLString &remoteURL, bool bModal=false, bool alwaysDefaultBrowser=false)
Definition: HelpSystem.cpp:237
ID_INSERTA
@ ID_INSERTA
Definition: LabelDialog.cpp:73
ComponentInterfaceSymbol
ComponentInterfaceSymbol pairs a persistent string identifier used internally with an optional,...
Definition: ComponentInterfaceSymbol.h:27
RowData::title
wxString title
Definition: LabelDialog.cpp:68
ShuttleGui::Id
ShuttleGui & Id(int id)
Definition: ShuttleGui.cpp:2274
LabelDialog::AddLabels
void AddLabels(const LabelTrack *t)
Definition: LabelDialog.cpp:472
LabelDialog::TransferDataToWindow
bool TransferDataToWindow() override
Definition: LabelDialog.cpp:293
AudacityTextEntryDialog.h
RowData::selectedRegion
SelectedRegion selectedRegion
Definition: LabelDialog.cpp:69
NumericConverter::LookupFormat
static NumericFormatSymbol LookupFormat(Type type, const wxString &id)
Definition: NumericTextCtrl.cpp:702
SelectedRegion::setT0
bool setT0(double t, bool maySwap=true)
Definition: SelectedRegion.h:115
LabelDialog.h
ViewInfo::selectedRegion
NotifyingSelectedRegion selectedRegion
Definition: ViewInfo.h:200
XXO
#define XXO(s)
Definition: Internat.h:44
eCancelButton
@ eCancelButton
Definition: ShuttleGui.h:601
ShuttleGuiBase::EndHorizontalLay
void EndHorizontalLay()
Definition: ShuttleGui.cpp:1177
ID_INSERTB
@ ID_INSERTB
Definition: LabelDialog.cpp:74
label
TranslatableString label
Definition: Tags.cpp:756
ShuttleGuiBase::StartHorizontalLay
void StartHorizontalLay(int PositionFlags=wxALIGN_CENTRE, int iProp=1)
Definition: ShuttleGui.cpp:1167
LabelStruct::selectedRegion
SelectedRegion selectedRegion
Definition: LabelTrack.h:70
FileNames::TextFiles
AUDACITY_DLL_API const FileType TextFiles
Definition: FileNames.h:77
ShuttleGuiBase::EndVerticalLay
void EndVerticalLay()
Definition: ShuttleGui.cpp:1203
ID_EXPORT
@ ID_EXPORT
Definition: LabelDialog.cpp:77
LabelDialog::OnCellChange
void OnCellChange(wxGridEvent &event)
Definition: LabelDialog.cpp:761
LabelDialog::mIndex
int mIndex
Definition: LabelDialog.h:107
ID_IMPORT
@ ID_IMPORT
Definition: LabelDialog.cpp:76
ShuttleGuiBase::AddFixedText
void AddFixedText(const TranslatableString &Str, bool bCenter=false, int wrapWidth=0)
Definition: ShuttleGui.cpp:440
name
const TranslatableString name
Definition: Distortion.cpp:98
RowData::index
int index
Definition: LabelDialog.cpp:67
LabelTrackView.h
NumericConverter::TIME
@ TIME
Definition: NumericTextCtrl.h:52
LabelDialog::mFreqFormat
NumericFormatSymbol mFreqFormat
Definition: LabelDialog.h:111
format
int format
Definition: ExportPCM.cpp:56
ShuttleGuiBase::GetParent
wxWindow * GetParent()
Definition: ShuttleGui.h:496
LabelTrackView::Get
static LabelTrackView & Get(LabelTrack &)
Definition: LabelTrackView.cpp:158
ShuttleGuiBase::AddWindow
wxWindow * AddWindow(wxWindow *pWindow, int PositionFlags=wxALIGN_CENTRE)
Definition: ShuttleGui.cpp:299
Col_Hfreq
@ Col_Hfreq
Definition: LabelDialog.cpp:54
LabelDialog::mTimeEditor
NumericEditor * mTimeEditor
Definition: LabelDialog.h:100
LabelDialog::FindInitialRow
void FindInitialRow()
Definition: LabelDialog.cpp:492
ShuttleGui.h
LabelDialog::Populate
void Populate()
Creates the dialog and its contents.
Definition: LabelDialog.cpp:215
ViewInfo.h
ShuttleGui::Prop
ShuttleGui & Prop(int iProp)
Definition: ShuttleGui.h:725
LabelTrack.h
NumericConverter::FREQUENCY
@ FREQUENCY
Definition: NumericTextCtrl.h:54
LabelDialog::OnChangeStime
void OnChangeStime(wxGridEvent &event, int row, RowData *rd)
Definition: LabelDialog.cpp:854
ShuttleGuiBase::AddButton
wxButton * AddButton(const TranslatableString &Text, int PositionFlags=wxALIGN_CENTRE, bool setDefault=false)
Definition: ShuttleGui.cpp:360
NumericEditor::SetRate
void SetRate(double rate)
Definition: Grid.cpp:241
NumericEditor
wxGridCellEditor for the NumericTextCtrl.
Definition: Grid.h:38
wxDialogWrapper
Definition: wxPanelWrapper.h:81
SelectedRegion::t0
double t0() const
Definition: SelectedRegion.h:94
Col_Stime
@ Col_Stime
Definition: LabelDialog.cpp:51
LabelTrack::GetNumLabels
int GetNumLabels() const
Definition: LabelTrack.cpp:921
FileConfig::Flush
virtual bool Flush(bool bCurrentOnly=false) wxOVERRIDE
Definition: FileConfig.cpp:143
eOkButton
@ eOkButton
Definition: ShuttleGui.h:600
LabelDialog::Show
bool Show(bool show=true) override
Definition: LabelDialog.cpp:356
LabelDialog::mProject
AudacityProject & mProject
Definition: LabelDialog.h:96
LabelDialog::OnChangeEtime
void OnChangeEtime(wxGridEvent &event, int row, RowData *rd)
Definition: LabelDialog.cpp:866
FileNames::SelectFile
AUDACITY_DLL_API FilePath SelectFile(Operation op, const TranslatableString &message, const FilePath &default_path, const FilePath &default_filename, const FileExtension &default_extension, const FileTypes &fileTypes, int flags, wxWindow *parent)
RowData
Definition: LabelDialog.cpp:61
_
#define _(s)
Definition: Internat.h:75
ChoiceEditor
Modified version of wxGridChoiceEditor using wxChoice instead of wxComboBox.
Definition: Grid.h:121
AudacityProject
The top-level handle to an Audacity project. It serves as a source of events that other objects can b...
Definition: Project.h:113
FileNames.h
AudacityMessageBox.h
LabelDialog::OnFreqUpdate
void OnFreqUpdate(wxCommandEvent &event)
Definition: LabelDialog.cpp:542
LabelDialog::OnImport
void OnImport(wxCommandEvent &event)
Definition: LabelDialog.cpp:630
LabelDialog::GetHelpPageName
ManualPageID GetHelpPageName()
Definition: LabelDialog.h:64
LabelDialog::OnRemove
void OnRemove(wxCommandEvent &event)
Definition: LabelDialog.cpp:592
RowData::RowData
RowData(int index_, const wxString &title_, const SelectedRegion &selectedRegion_)
Definition: LabelDialog.cpp:63
LabelTrack::GetLabel
const LabelStruct * GetLabel(int index) const
Definition: LabelTrack.cpp:926
ShuttleGui::AddStandardButtons
void AddStandardButtons(long buttons=eOkButton|eCancelButton, wxWindow *extra=NULL)
Definition: ShuttleGui.cpp:2432
LabelDialog::ReadSize
void ReadSize()
Definition: LabelDialog.cpp:902
LabelDialog::OnUpdate
void OnUpdate(wxCommandEvent &event)
Definition: LabelDialog.cpp:532
LabelDialog::OnChangeTrack
void OnChangeTrack(wxGridEvent &event, int row, RowData *rd)
Definition: LabelDialog.cpp:812
LabelDialog::mRate
double mRate
Definition: LabelDialog.h:110
ChoiceEditor::SetChoices
void SetChoices(const wxArrayString &choices)
Definition: Grid.cpp:454
NumericEditor::SetFormat
void SetFormat(const NumericFormatSymbol &format)
Definition: Grid.cpp:236
NotifyingSelectedRegion::t0
double t0() const
Definition: ViewInfo.h:45
Prefs.h
ProjectWindow.h
TranslatableString::Translation
wxString Translation() const
Definition: TranslatableString.h:79
LabelDialog::OnCancel
void OnCancel(wxCommandEvent &event)
Definition: LabelDialog.cpp:938
ProjectWindow::RedrawProject
void RedrawProject(const bool bForceWaveTracks=false)
Definition: ProjectWindow.cpp:708
TrackList::Any
auto Any() -> TrackIterRange< TrackType >
Definition: Track.h:1355
LabelDialog::WriteSize
void WriteSize()
Definition: LabelDialog.cpp:914
LabelDialog::mChoiceEditor
ChoiceEditor * mChoiceEditor
Definition: LabelDialog.h:99
Column
Column
Definition: LabelDialog.cpp:48
LabelDialog::mInitialRow
int mInitialRow
Definition: LabelDialog.h:113
safenew
#define safenew
Definition: MemoryX.h:10
LabelDialog::mTrackNames
wxArrayString mTrackNames
Definition: LabelDialog.h:109
END_EVENT_TABLE
END_EVENT_TABLE()
LabelDialog::mFormat
NumericFormatSymbol mFormat
Definition: LabelDialog.h:111
SelectedRegion::setT1
bool setT1(double t, bool maySwap=true)
Definition: SelectedRegion.h:127
LabelTrackView::ResetTextSelection
void ResetTextSelection()
Definition: LabelTrackView.cpp:1005
LabelDialog::mTracks
TrackList * mTracks
Definition: LabelDialog.h:105
LabelDialog::TransferDataFromWindow
bool TransferDataFromWindow() override
Definition: LabelDialog.cpp:375
ShuttleGui
Derived from ShuttleGuiBase, an Audacity specific class for shuttling data to and from GUI.
Definition: ShuttleGui.h:631
SelectedRegion
Defines a selected portion of a project.
Definition: SelectedRegion.h:38
LabelDialog::PopulateOrExchange
void PopulateOrExchange(ShuttleGui &S)
Definition: LabelDialog.cpp:255