1 /**********************************************************************
2
3 Audacity - A Digital Audio Editor
4 Copyright 1999-2009 Audacity Team
5 License: wxwidgets
6
7 Dan Horgan
8 James Crook
9
10 ******************************************************************//**
11
12 \file SelectCommand.cpp
13 \brief Definitions for SelectCommand classes
14
15 \class SelectTimeCommand
16 \brief Command for changing the time selection
17
18 \class SelectFrequenciesCommand
19 \brief Command for changing the frequency selection
20
21 \class SelectTracksCommand
22 \brief Command for changing the selection of tracks
23
24 \class SelectCommand
25 \brief Command for changing time, frequency and track selection. This
26 class is a little baroque, as it uses the SelectTimeCommand,
27 SelectFrequenciesCommand and SelectTracksCommand, when it could just
28 explicitly code all three.
29
30 *//*******************************************************************/
31
32
33 #include "SelectCommand.h"
34
35 #include <wx/string.h>
36 #include <float.h>
37
38 #include "LoadCommands.h"
39 #include "../ProjectSelectionManager.h"
40 #include "../TrackPanel.h"
41 #include "../Shuttle.h"
42 #include "../ShuttleGui.h"
43 #include "../effects/Effect.h"
44 #include "ViewInfo.h"
45 #include "CommandContext.h"
46
47
48 const ComponentInterfaceSymbol SelectTimeCommand::Symbol
49 { XO("Select Time") };
50
51 namespace{ BuiltinCommandsModule::Registration< SelectTimeCommand > reg; }
52
53 // Relative to project and relative to selection cover MOST options, since you can already
54 // set a selection to a clip.
55 const int nRelativeTos =6;
56 static const EnumValueSymbol kRelativeTo[nRelativeTos] =
57 {
58 { wxT("ProjectStart"), XO("Project Start") },
59 { XO("Project") },
60 { wxT("ProjectEnd"), XO("Project End") },
61 { wxT("SelectionStart"), XO("Selection Start") },
62 { XO("Selection") },
63 { wxT("SelectionEnd"), XO("Selection End") }
64 };
65
DefineParams(ShuttleParams & S)66 bool SelectTimeCommand::DefineParams( ShuttleParams & S ){
67 // Allow selection down to -ve 100seconds.
68 // Typically used to expand/contract selections by a small amount.
69 S.OptionalY( bHasT0 ).Define( mT0, wxT("Start"), 0.0, -100.0, (double)FLT_MAX);
70 S.OptionalY( bHasT1 ).Define( mT1, wxT("End"), 0.0, -100.0, (double)FLT_MAX);
71 S.OptionalN( bHasRelativeSpec ).DefineEnum( mRelativeTo, wxT("RelativeTo"), 0, kRelativeTo, nRelativeTos );
72 return true;
73 }
74
PopulateOrExchange(ShuttleGui & S)75 void SelectTimeCommand::PopulateOrExchange(ShuttleGui & S)
76 {
77 S.AddSpace(0, 5);
78
79 S.StartMultiColumn(3, wxEXPAND);
80 {
81 S.SetStretchyCol( 2 );
82 S.Optional( bHasT0 ).TieTextBox(XXO("Start Time:"), mT0);
83 S.Optional( bHasT1 ).TieTextBox(XXO("End Time:"), mT1);
84 // Chooses what time is relative to.
85 S.Optional( bHasRelativeSpec ).TieChoice(
86 XXO("Relative To:"),
87 mRelativeTo, Msgids( kRelativeTo, nRelativeTos ));
88 }
89 S.EndMultiColumn();
90 }
91
Apply(const CommandContext & context)92 bool SelectTimeCommand::Apply(const CommandContext & context){
93 // Many commands need focus on track panel.
94 // No harm in setting it with a scripted select.
95 TrackPanel::Get( context.project ).SetFocus();
96 if( !bHasT0 && !bHasT1 )
97 return true;
98
99 // Defaults if no value...
100 if( !bHasT0 )
101 mT0 = 0.0;
102 if( !bHasT1 )
103 mT1 = 0.0;
104 if( !bHasRelativeSpec )
105 mRelativeTo = 0;
106
107 AudacityProject * p = &context.project;
108 double end = TrackList::Get( *p ).GetEndTime();
109 double t0;
110 double t1;
111
112 auto &selectedRegion = ViewInfo::Get( *p ).selectedRegion;
113 switch( bHasRelativeSpec ? mRelativeTo : 0 ){
114 default:
115 case 0: //project start
116 t0 = mT0;
117 t1 = mT1;
118 break;
119 case 1: //project
120 t0 = mT0;
121 t1 = end + mT1;
122 break;
123 case 2: //project end;
124 t0 = end - mT0;
125 t1 = end - mT1;
126 break;
127 case 3: //selection start
128 t0 = mT0 + selectedRegion.t0();
129 t1 = mT1 + selectedRegion.t0();
130 break;
131 case 4: //selection
132 t0 = mT0 + selectedRegion.t0();
133 t1 = mT1 + selectedRegion.t1();
134 break;
135 case 5: //selection end
136 t0 = selectedRegion.t1() - mT0;
137 t1 = selectedRegion.t1() - mT1;
138 break;
139 }
140
141 selectedRegion.setTimes( t0, t1 );
142 return true;
143 }
144
145 const ComponentInterfaceSymbol SelectFrequenciesCommand::Symbol
146 { XO("Select Frequencies") };
147
148 namespace{ BuiltinCommandsModule::Registration< SelectFrequenciesCommand > reg2; }
149
DefineParams(ShuttleParams & S)150 bool SelectFrequenciesCommand::DefineParams( ShuttleParams & S ){
151 S.OptionalN( bHasTop ).Define( mTop, wxT("High"), 0.0, 0.0, (double)FLT_MAX);
152 S.OptionalN( bHasBottom ).Define( mBottom, wxT("Low"), 0.0, 0.0, (double)FLT_MAX);
153 return true;
154 }
155
PopulateOrExchange(ShuttleGui & S)156 void SelectFrequenciesCommand::PopulateOrExchange(ShuttleGui & S)
157 {
158 S.AddSpace(0, 5);
159
160 S.StartMultiColumn(3, wxEXPAND);
161 {
162 S.SetStretchyCol( 2 );
163 S.Optional( bHasTop ).TieTextBox(XXO("High:"), mTop);
164 S.Optional( bHasBottom ).TieTextBox(XXO("Low:"), mBottom);
165 }
166 S.EndMultiColumn();
167 }
168
Apply(const CommandContext & context)169 bool SelectFrequenciesCommand::Apply(const CommandContext & context){
170 if( !bHasBottom && !bHasTop )
171 return true;
172
173 // Defaults if no value...
174 if( !bHasTop )
175 mTop = 0.0;
176 if( !bHasBottom )
177 mBottom = 0.0;
178
179 ProjectSelectionManager::Get( context.project ).SSBL_ModifySpectralSelection(
180 mBottom, mTop, false);// false for not done.
181 return true;
182 }
183
184 const ComponentInterfaceSymbol SelectTracksCommand::Symbol
185 { XO("Select Tracks") };
186
187 namespace{ BuiltinCommandsModule::Registration< SelectTracksCommand > reg3; }
188
189 const int nModes =3;
190 static const EnumValueSymbol kModes[nModes] =
191 {
192 // These are acceptable dual purpose internal/visible names
193
194 /* i18n-hint verb, imperative */
195 { XO("Set") },
196 { XO("Add") },
197 { XO("Remove") },
198 };
199
DefineParams(ShuttleParams & S)200 bool SelectTracksCommand::DefineParams( ShuttleParams & S ){
201 S.OptionalN( bHasFirstTrack).Define( mFirstTrack, wxT("Track"), 0.0, 0.0, 100.0);
202 S.OptionalN( bHasNumTracks ).Define( mNumTracks, wxT("TrackCount"), 1.0, 0.0, 100.0);
203 S.OptionalY( bHasMode ).DefineEnum( mMode, wxT("Mode"), 0, kModes, nModes );
204
205 return true;
206 }
207
PopulateOrExchange(ShuttleGui & S)208 void SelectTracksCommand::PopulateOrExchange(ShuttleGui & S)
209 {
210 S.AddSpace(0, 5);
211
212 S.StartMultiColumn(3, wxEXPAND);
213 {
214 S.SetStretchyCol( 2 );
215 S.Optional( bHasFirstTrack).TieTextBox(XXO("First Track:"),mFirstTrack);
216 S.Optional( bHasNumTracks).TieTextBox(XXO("Track Count:"),mNumTracks);
217 }
218 S.EndMultiColumn();
219 S.StartMultiColumn(2, wxALIGN_CENTER);
220 {
221 // Always used, so no check box.
222 S.TieChoice( XXO("Mode:"), mMode, Msgids( kModes, nModes ));
223 }
224 S.EndMultiColumn();
225 }
226
Apply(const CommandContext & context)227 bool SelectTracksCommand::Apply(const CommandContext &context)
228 {
229
230 // Count selection as a do-nothing effect.
231 // Used to invalidate cached selection and tracks.
232 Effect::IncEffectCounter();
233 int index = 0;
234 auto &tracks = TrackList::Get( context.project );
235
236 // Defaults if no value...
237 if( !bHasNumTracks )
238 mNumTracks = 1.0;
239 if( !bHasFirstTrack )
240 mFirstTrack = 0.0;
241
242 // Multiple channels count as fractions of a track.
243 double last = mFirstTrack+mNumTracks;
244 double first = mFirstTrack;
245
246 for (auto t : tracks.Leaders()) {
247 auto channels = TrackList::Channels(t);
248 double term = 0.0;
249 // Add 0.01 so we are free of rounding errors in comparisons.
250 constexpr double fudge = 0.01;
251 for (auto channel : channels) {
252 double track = index + fudge + term;
253 bool sel = first <= track && track <= last;
254 if( mMode == 0 ){ // Set
255 channel->SetSelected(sel);
256 }
257 else if( mMode == 1 && sel ){ // Add
258 channel->SetSelected(sel);
259 }
260 else if( mMode == 2 && sel ){ // Remove
261 channel->SetSelected(!sel);
262 }
263 term += 1.0 / channels.size();
264 }
265 ++index;
266 }
267 return true;
268 }
269
270 const ComponentInterfaceSymbol SelectCommand::Symbol
271 { XO("Select") };
272
273 namespace{ BuiltinCommandsModule::Registration< SelectCommand > reg4; }
274