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