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