1 /**********************************************************************
2 
3  Audacity: A Digital Audio Editor
4 
5  SelectUtilities.cpp
6 
7  Paul Licameli split from SelectMenus.cpp
8 
9  **********************************************************************/
10 
11 #include "SelectUtilities.h"
12 
13 #include <wx/frame.h>
14 
15 #include "widgets/AudacityMessageBox.h"
16 #include "AudioIO.h"
17 #include "CommonCommandFlags.h"
18 #include "Menus.h"
19 #include "Project.h"
20 #include "ProjectAudioIO.h"
21 #include "ProjectHistory.h"
22 #include "ProjectWindows.h"
23 #include "ProjectRate.h"
24 #include "ProjectSettings.h"
25 #include "SelectionState.h"
26 #include "TimeDialog.h"
27 #include "TrackPanelAx.h"
28 #include "TrackPanel.h"
29 #include "ViewInfo.h"
30 #include "WaveTrack.h"
31 
32 #include "commands/CommandManager.h"
33 
34 namespace {
35 
36 // Temporal selection (not TimeTrack selection)
37 // potentially for all wave tracks.
DoSelectTimeAndAudioTracks(AudacityProject & project,bool bAllTime,bool bAllTracks)38 void DoSelectTimeAndAudioTracks
39 (AudacityProject &project, bool bAllTime, bool bAllTracks)
40 {
41    auto &tracks = TrackList::Get( project );
42    auto &selectedRegion = ViewInfo::Get( project ).selectedRegion;
43 
44    if( bAllTime )
45       selectedRegion.setTimes(
46          tracks.GetMinOffset(), tracks.GetEndTime());
47 
48    if( bAllTracks ) {
49       // Unselect all tracks before selecting audio.
50       for (auto t : tracks.Any())
51          t->SetSelected(false);
52       for (auto t : tracks.Any<WaveTrack>())
53          t->SetSelected(true);
54 
55       ProjectHistory::Get( project ).ModifyState(false);
56    }
57 }
58 
59 }
60 namespace SelectUtilities {
61 
DoSelectTimeAndTracks(AudacityProject & project,bool bAllTime,bool bAllTracks)62 void DoSelectTimeAndTracks
63 (AudacityProject &project, bool bAllTime, bool bAllTracks)
64 {
65    auto &tracks = TrackList::Get( project );
66    auto &selectedRegion = ViewInfo::Get( project ).selectedRegion;
67 
68    if( bAllTime )
69       selectedRegion.setTimes(
70          tracks.GetMinOffset(), tracks.GetEndTime());
71 
72    if( bAllTracks ) {
73       for (auto t : tracks.Any())
74          t->SetSelected(true);
75 
76       ProjectHistory::Get( project ).ModifyState(false);
77    }
78 }
79 
SelectNone(AudacityProject & project)80 void SelectNone( AudacityProject &project )
81 {
82    auto &tracks = TrackList::Get( project );
83    for (auto t : tracks.Any())
84       t->SetSelected(false);
85 
86    auto &trackPanel = TrackPanel::Get( project );
87    trackPanel.Refresh(false);
88 }
89 
90 // Select the full time range, if no
91 // time range is selected.
SelectAllIfNone(AudacityProject & project)92 void SelectAllIfNone( AudacityProject &project )
93 {
94    auto &viewInfo = ViewInfo::Get( project );
95    auto flags = MenuManager::Get( project ).GetUpdateFlags();
96    if((flags & EditableTracksSelectedFlag()).none() ||
97       viewInfo.selectedRegion.isPoint())
98       DoSelectAllAudio( project );
99 }
100 
101 // Select the full time range, if no time range is selected and
102 // selecting is allowed. Returns "false" selecting not allowed.
SelectAllIfNoneAndAllowed(AudacityProject & project)103 bool SelectAllIfNoneAndAllowed( AudacityProject &project )
104 {
105    auto allowed = gPrefs->ReadBool(wxT("/GUI/SelectAllOnNone"), false);
106    auto &viewInfo = ViewInfo::Get( project );
107    auto flags = MenuManager::Get( project ).GetUpdateFlags();
108 
109    if((flags & EditableTracksSelectedFlag()).none() ||
110       viewInfo.selectedRegion.isPoint()) {
111       if (!allowed) {
112          return false;
113       }
114       DoSelectAllAudio( project );
115    }
116    return true;
117 }
118 
DoListSelection(AudacityProject & project,Track * t,bool shift,bool ctrl,bool modifyState)119 void DoListSelection
120 (AudacityProject &project, Track *t, bool shift, bool ctrl, bool modifyState)
121 {
122    auto &tracks = TrackList::Get( project );
123    auto &selectionState = SelectionState::Get( project );
124    const auto &settings = ProjectSettings::Get( project );
125    auto &viewInfo = ViewInfo::Get( project );
126    auto &window = GetProjectFrame( project );
127 
128    auto isSyncLocked = settings.IsSyncLocked();
129 
130    selectionState.HandleListSelection(
131       tracks, viewInfo, *t,
132       shift, ctrl, isSyncLocked );
133 
134    if (! ctrl )
135       TrackFocus::Get( project ).Set( t );
136    window.Refresh(false);
137    if (modifyState)
138       ProjectHistory::Get( project ).ModifyState(true);
139 }
140 
DoSelectAll(AudacityProject & project)141 void DoSelectAll(AudacityProject &project)
142 {
143    DoSelectTimeAndTracks( project, true, true );
144 }
145 
DoSelectAllAudio(AudacityProject & project)146 void DoSelectAllAudio(AudacityProject &project)
147 {
148    DoSelectTimeAndAudioTracks( project, true, true );
149 }
150 
151 // This function selects all tracks if no tracks selected,
152 // and all time if no time selected.
153 // There is an argument for making it just count wave tracks,
154 // However you could then not select a label and cut it,
155 // without this function selecting all tracks.
DoSelectSomething(AudacityProject & project)156 void DoSelectSomething(AudacityProject &project)
157 {
158    auto &tracks = TrackList::Get( project );
159    auto &selectedRegion = ViewInfo::Get( project ).selectedRegion;
160 
161    bool bTime = selectedRegion.isPoint();
162    bool bTracks = tracks.Selected().empty();
163 
164    if( bTime || bTracks )
165       DoSelectTimeAndTracks( project, bTime, bTracks );
166 }
167 
ActivatePlayRegion(AudacityProject & project)168 void ActivatePlayRegion(AudacityProject &project)
169 {
170    auto &tracks = TrackList::Get( project );
171 
172    auto &viewInfo = ViewInfo::Get( project );
173    auto &playRegion = viewInfo.playRegion;
174    playRegion.SetActive( true );
175    if (playRegion.Empty()) {
176       auto &selectedRegion = viewInfo.selectedRegion;
177       if (!selectedRegion.isPoint())
178          playRegion.SetTimes(selectedRegion.t0(), selectedRegion.t1());
179       else
180          // Arbitrary first four seconds
181          playRegion.SetTimes(0.0, 4.0);
182    }
183 
184    // Ensure the proper state of looping in the menu
185    CommandManager::Get( project ).UpdateCheckmarks( project );
186 }
187 
InactivatePlayRegion(AudacityProject & project)188 void InactivatePlayRegion(AudacityProject &project)
189 {
190    auto &viewInfo = ViewInfo::Get( project );
191    auto &playRegion = viewInfo.playRegion;
192    auto &selectedRegion = viewInfo.selectedRegion;
193    // Set only the times that are fetched by the playback engine, but not
194    // the last-active times that are used for display.
195    playRegion.SetActive( false );
196    playRegion.SetTimes( selectedRegion.t0(), selectedRegion.t1() );
197 
198    // Ensure the proper state of looping in the menu
199    CommandManager::Get( project ).UpdateCheckmarks( project );
200 }
201 
TogglePlayRegion(AudacityProject & project)202 void TogglePlayRegion(AudacityProject &project)
203 {
204    auto &viewInfo = ViewInfo::Get( project );
205    auto &playRegion = viewInfo.playRegion;
206    if (playRegion.Active())
207       InactivatePlayRegion(project);
208    else
209       ActivatePlayRegion(project);
210 }
211 
ClearPlayRegion(AudacityProject & project)212 void ClearPlayRegion(AudacityProject &project)
213 {
214    auto &viewInfo = ViewInfo::Get( project );
215    auto &playRegion = viewInfo.playRegion;
216    playRegion.Clear();
217 }
218 
SetPlayRegionToSelection(AudacityProject & project)219 void SetPlayRegionToSelection(AudacityProject &project)
220 {
221    auto &viewInfo = ViewInfo::Get( project );
222    auto &playRegion = viewInfo.playRegion;
223    auto &selectedRegion = viewInfo.selectedRegion;
224    playRegion.SetAllTimes( selectedRegion.t0(), selectedRegion.t1() );
225 }
226 
OnSetRegion(AudacityProject & project,bool left,bool selection,const TranslatableString & dialogTitle)227 void OnSetRegion(AudacityProject &project,
228    bool left, bool selection, const TranslatableString &dialogTitle)
229 {
230    auto token = ProjectAudioIO::Get( project ).GetAudioIOToken();
231    auto &viewInfo = ViewInfo::Get( project );
232    auto &playRegion = viewInfo.playRegion;
233    auto &selectedRegion = viewInfo.selectedRegion;
234    const auto &settings = ProjectSettings::Get( project );
235    auto &window = GetProjectFrame( project );
236 
237    const auto getValue = [&]() -> double {
238       if (selection) {
239          if (left)
240             return selectedRegion.t0();
241          else
242             return selectedRegion.t1();
243       }
244       else {
245          if (left)
246             return playRegion.GetStart();
247          else
248             return playRegion.GetEnd();
249       }
250    };
251 
252    const auto setValue = [&](double value){
253       if (selection) {
254          if (left)
255             selectedRegion.setT0(value, false);
256          else
257             selectedRegion.setT1(value, false);
258       }
259       else {
260          if (left)
261             playRegion.SetStart(value);
262          else
263             playRegion.SetEnd(value);
264       }
265    };
266 
267    bool bSelChanged = false;
268    auto gAudioIO = AudioIO::Get();
269    if ((token > 0) && gAudioIO->IsStreamActive(token))
270    {
271       double indicator = gAudioIO->GetStreamTime();
272       setValue(indicator);
273       bSelChanged = true;
274    }
275    else
276    {
277       auto fmt = settings.GetSelectionFormat();
278       auto rate = ProjectRate::Get(project).GetRate();
279 
280       TimeDialog dlg(&window, dialogTitle,
281          fmt, rate, getValue(), XO("Position"));
282 
283       if (wxID_OK == dlg.ShowModal())
284       {
285          //Get the value from the dialog
286          setValue( std::max(0.0, dlg.GetTimeValue()) );
287          bSelChanged = true;
288       }
289    }
290 
291    if (bSelChanged)
292       ProjectHistory::Get( project ).ModifyState(false);
293 }
294 }
295