3#include "../AdornedRulerPanel.h"
5#include "../CommonCommandFlags.h"
6#include "../SpectrumAnalyst.h"
9#include "../ProjectAudioIO.h"
10#include "../ProjectAudioManager.h"
13#include "../ProjectSelectionManager.h"
14#include "../ProjectSettings.h"
15#include "../ProjectWindow.h"
16#include "../ProjectWindows.h"
17#include "../SelectUtilities.h"
18#include "../SyncLock.h"
19#include "../TrackPanel.h"
20#include "../WaveTrack.h"
21#include "../LabelTrack.h"
22#include "../commands/CommandContext.h"
23#include "../commands/CommandManager.h"
24#include "../toolbars/ControlToolBar.h"
25#include "../tracks/ui/SelectHandle.h"
26#include "../tracks/labeltrack/ui/LabelTrackView.h"
27#include "../tracks/playabletrack/wavetrack/ui/WaveTrackView.h"
28#include "../tracks/playabletrack/wavetrack/ui/WaveTrackViewConstants.h"
40 for (
auto wt : tracks.Selected<
const WaveTrack >() ) {
42 bool hasSpectrum = (displays.end() != std::find(
43 displays.begin(), displays.end(),
66 auto windowSize = size_t(std::max(1.0, rate / 100));
67 Floats dist{ windowSize,
true };
70 for (
auto one : tracks.Selected<
const WaveTrack >()) {
71 auto oneWindowSize = size_t(std::max(1.0, one->GetRate() / 100));
72 Floats oneDist{ oneWindowSize };
73 auto s = one->TimeToLongSamples(t0);
76 one->GetFloats(oneDist.get(),
77 s - (
int)oneWindowSize/2, oneWindowSize,
fillTwo);
82 for(
size_t i=0; i<oneWindowSize; i++){
83 float fDist = fabs( oneDist[i]);
84 if( prev * oneDist[i] > 0 )
95 for(
size_t i = 0; i < windowSize; i++) {
97 if (windowSize != oneWindowSize)
98 j = i * (oneWindowSize-1) / (windowSize-1);
102 dist[i] += oneDist[j];
106 0.1 * (abs(
int(i) -
int(windowSize/2))) /
float(windowSize/2);
114 for(
size_t i=0; i<windowSize; i++) {
122 if(( nTracks == 1 ) && (
min > (0.2*nTracks) ))
125 if(( nTracks > 1 ) && (
min > (0.6*nTracks) ))
128 return t0 + (argmin - (int)windowSize/2) / rate;
136 auto &project = context.
project;
137 auto evt = context.
pEvt;
138 bool bKeyUp = (evt) && evt->GetEventType() == wxEVT_KEY_UP;
167 wxLongLong mLastSelectionAdjustment { ::wxGetUTCTimeMillis() };
168 double mSeekShort{ 0.0 };
169 double mSeekLong{ 0.0 };
175#ifdef EXPERIMENTAL_IMPROVED_SEEKING
176 if (gAudioIO->GetLastPlaybackTime() < lastSelectionAdjustment) {
183 lastSelectionAdjustment = ::wxGetUTCTimeMillis();
185 gAudioIO->SeekStream(seekStep);
208 if (std::abs(viewInfo.TimeToPosition(result) - viewInfo.TimeToPosition(t))
213 result = viewInfo.OffsetTimeByPixels(t, minPix);
221 double t,
double offset,
TimeUnit timeUnit,
int snapToTime)
229 return viewInfo.OffsetTimeByPixels(t, (
int)offset);
231 return GridMove(project, t, (
int)offset);
246 int snapToTime =
settings.GetSnapTo();
247 const double t0 = viewInfo.selectedRegion.t0();
248 const double end = std::max(
250 viewInfo.GetScreenEndTime());
254 if( viewInfo.selectedRegion.isPoint() )
257 t0, seekStep, timeUnit, snapToTime);
259 newT = std::max(0.0, newT);
262 viewInfo.selectedRegion.setT0(
265 viewInfo.selectedRegion.collapseToT0();
268 trackPanel.DrawOverlays(
false);
269 ruler.DrawOverlays(
false);
275 viewInfo.selectedRegion.collapseToT0();
277 viewInfo.selectedRegion.collapseToT1();
278 trackPanel.Refresh(
false);
282 window.ScrollIntoView(viewInfo.selectedRegion.t1());
301 int snapToTime =
settings.GetSnapTo();
302 const double t0 = viewInfo.selectedRegion.t0();
303 const double t1 = viewInfo.selectedRegion.t1();
304 const double end = std::max(
306 viewInfo.GetScreenEndTime());
313 bMoveT0 ? t0 : t1, seekStep, timeUnit, snapToTime);
315 newT = std::max( 0.0, newT );
319 newT = bMoveT0 ?
std::min( t1, newT ) : std::max( t0, newT );
323 viewInfo.selectedRegion.setT0( newT );
325 viewInfo.selectedRegion.setT1( newT );
328 window.ScrollIntoView(newT);
355 const wxLongLong curtime = ::wxGetUTCTimeMillis();
356 enum { MIN_INTERVAL = 50 };
363 enum { LARGER_MULTIPLIER = 4 };
364 const double seekStep = (fast ? LARGER_MULTIPLIER : 1.0) * direction;
372 wxLongLong &lastSelectionAdjustment)
379 lastSelectionAdjustment = ::wxGetUTCTimeMillis();
397 wxLongLong curtime = ::wxGetUTCTimeMillis();
407 bool bMoveT0 = (step < 0 );
412 double indicator = gAudioIO->GetStreamTime();
414 viewInfo.selectedRegion.setT0(indicator,
false);
416 viewInfo.selectedRegion.setT1(indicator);
422 const double t0 = viewInfo.selectedRegion.t0();
423 const double t1 = viewInfo.selectedRegion.t1();
424 const double end = std::max(
426 viewInfo.GetScreenEndTime());
428 double newT = viewInfo.OffsetTimeByPixels( bMoveT0 ? t0 : t1, pixels);
430 newT = std::max( 0.0, newT );
438 viewInfo.selectedRegion.setT0( newT );
440 viewInfo.selectedRegion.setT1( newT );
443 window.ScrollIntoView(newT);
466 for (
auto lt : tracks.Selected<
LabelTrack >()) {
468 if (view.SelectAllText(context.
project)) {
469 trackPanel.Refresh(
false);
476 for (
auto wt : tracks.Any<
WaveTrack>()) {
478 if (view.SelectAllText(context.
project)) {
479 trackPanel.Refresh(
false);
489 auto &project = context.
project;
499 auto &project = context.
project;
505 auto &project = context.
project;
508 bool selected =
false;
511 t->SetSelected(
true);
522 true,
true,
XO(
"Set Left Selection Boundary"));
528 false,
true,
XO(
"Set Right Selection Boundary"));
533 auto &project = context.
project;
537 double kWayOverToRight = std::numeric_limits<double>::max();
539 auto range = tracks.Selected();
546 (kWayOverToRight * (1 - std::numeric_limits<double>::epsilon()) ))
549 selectedRegion.setT0(minOffset);
556 auto &project = context.
project;
560 double kWayOverToLeft = std::numeric_limits<double>::lowest();
562 auto range = tracks.Selected();
569 (kWayOverToLeft * (1 - std::numeric_limits<double>::epsilon()) ))
572 selectedRegion.setT1(maxEndOffset);
579 auto &project = context.
project;
583 auto range = tracks.Selected();
587 if( maxEndOffset < minOffset)
590 viewInfo.selectedRegion.setTimes( minOffset, maxEndOffset );
599 auto &project = context.
project;
607 auto &project = context.
project;
616 window.ScrollIntoView(selectedRegion.t0());
621#ifdef EXPERIMENTAL_SPECTRAL_EDITING
629 auto &project = context.
project;
632 const double f0 = selectedRegion.
f0();
633 const double f1 = selectedRegion.f1();
634 const bool haveSpectralSelection =
637 if (haveSpectralSelection)
641 selectedRegion.setFrequencies
645 selectedRegion.setFrequencies(mLastF0, mLastF1);
652 auto &project = context.
project;
658 auto &project = context.
project;
669 auto &project = context.
project;
675 double cursorPositionCurrent = isAudioActive
676 ? gAudioIO->GetStreamTime()
677 : selectedRegion.t0();
678 selectedRegion.setTimes(
688 auto &project = context.
project;
694 isAudioActive ? gAudioIO->GetStreamTime() : selectedRegion.t0();
700 auto &project = context.
project;
704 if (selectedRegion.isPoint())
705 selectedRegion.setTimes(t0, t0);
710 selectedRegion.setTimes(t0, t1);
718 auto &project = context.
project;
724 auto &project = context.
project;
730 auto &project = context.
project;
736 auto &project = context.
project;
744 auto &project = context.
project;
746 window.SkipEnd(
true);
793 auto &project = context.
project;
797 selectedRegion.collapseToT0();
799 window.ScrollIntoView(selectedRegion.t0());
804 auto &project = context.
project;
808 selectedRegion.collapseToT1();
810 window.ScrollIntoView(selectedRegion.t1());
815 auto &project = context.
project;
820 double kWayOverToRight = std::numeric_limits<double>::max();
823 if (trackRange.empty())
831 (kWayOverToRight * (1 - std::numeric_limits<double>::epsilon()) ))
834 selectedRegion.setTimes(minOffset, minOffset);
836 window.ScrollIntoView(selectedRegion.t0());
841 auto &project = context.
project;
846 double kWayOverToLeft = std::numeric_limits<double>::lowest();
849 if (trackRange.empty())
857 (kWayOverToLeft * (1 - std::numeric_limits<double>::epsilon()) ))
860 selectedRegion.setTimes(maxEndOffset, maxEndOffset);
862 window.ScrollIntoView(selectedRegion.t1());
867 auto &project = context.
project;
871 controlToolBar.OnRewind(evt);
877 auto &project = context.
project;
881 controlToolBar.OnFF(evt);
925 auto &project = context.
project;
931 auto &project = context.
project;
937 auto &project = context.
project;
943 auto &project = context.
project;
951 auto &project = context.
project;
958 gPrefs->Read(wxT(
"/AudioIO/SeekShortPeriod"), &
mSeekInfo.mSeekShort, 1.0);
959 gPrefs->Read(wxT(
"/AudioIO/SeekLongPeriod"), &
mSeekInfo.mSeekLong, 15.0);
976 return std::make_unique< SelectActions::Handler >(); } };
984#define FN(X) (& SelectActions::Handler :: X)
994 Menu( wxT(
"Select"),
XXO(
"&Select"),
996 Command( wxT(
"SelectAll"),
XXO(
"&All"),
FN(OnSelectAll),
998 Options{ wxT(
"Ctrl+A"),
XO(
"Select All") } ),
999 Command( wxT(
"SelectNone"),
XXO(
"&None"),
FN(OnSelectNone),
1001 Options{ wxT(
"Ctrl+Shift+A"),
XO(
"Select None") } ),
1005 Menu( wxT(
"Tracks"),
XXO(
"&Tracks"),
1006 Command( wxT(
"SelAllTracks"),
XXO(
"In All &Tracks"),
1007 FN(OnSelectAllTracks),
1009 wxT(
"Ctrl+Shift+K") )
1011 #ifdef EXPERIMENTAL_SYNC_LOCK
1013 Command( wxT(
"SelSyncLockTracks"),
XXO(
"In All &Sync-Locked Tracks"),
1014 FN(OnSelectSyncLockSel),
1016 Options{ wxT(
"Ctrl+Shift+Y"),
XO(
"Select Sync-Locked") } )
1022 Menu( wxT(
"Region"),
XXO(
"R&egion"),
1024 Command( wxT(
"SetLeftSelection"),
XXO(
"&Left at Playback Position"),
1026 Options{ wxT(
"["),
XO(
"Set Selection Left at Play Position") } ),
1027 Command( wxT(
"SetRightSelection"),
XXO(
"&Right at Playback Position"),
1029 Options{ wxT(
"]"),
XO(
"Set Selection Right at Play Position") } ),
1030 Command( wxT(
"SelTrackStartToCursor"),
XXO(
"Track &Start to Cursor"),
1032 Options{ wxT(
"Shift+J"),
XO(
"Select Track Start to Cursor") } ),
1033 Command( wxT(
"SelCursorToTrackEnd"),
XXO(
"Cursor to Track &End"),
1035 Options{ wxT(
"Shift+K"),
XO(
"Select Cursor to Track End") } ),
1036 Command( wxT(
"SelTrackStartToEnd"),
XXO(
"Track Start to En&d"),
1038 Options{}.LongName(
XO(
"Select Track Start to End") ) )
1047 Command( wxT(
"SelSave"),
XXO(
"S&tore Selection"),
FN(OnSelectionSave),
1050 Command( wxT(
"SelRestore"),
XXO(
"Retrieve Selectio&n"),
1057 #ifdef EXPERIMENTAL_SPECTRAL_EDITING
1058 Menu( wxT(
"Spectral"),
XXO(
"S&pectral"),
1059 Command( wxT(
"ToggleSpectralSelection"),
1060 XXO(
"To&ggle Spectral Selection"),
FN(OnToggleSpectralSelection),
1062 Command( wxT(
"NextHigherPeakFrequency"),
1063 XXO(
"Next &Higher Peak Frequency"),
FN(OnNextHigherPeakFrequency),
1065 Command( wxT(
"NextLowerPeakFrequency"),
1066 XXO(
"Next &Lower Peak Frequency"),
FN(OnNextLowerPeakFrequency),
1073 Command( wxT(
"SelCursorStoredCursor"),
1074 XXO(
"Cursor to Stored &Cursor Position"),
1076 Options{}.LongName(
XO(
"Select Cursor to Stored") ) ),
1078 Command( wxT(
"StoreCursorPosition"),
XXO(
"Store Cursor Pos&ition"),
1079 FN(OnCursorPositionStore),
1086 Command( wxT(
"ZeroCross"),
XXO(
"At &Zero Crossings"),
1088 Options{ wxT(
"Z"),
XO(
"Select Zero Crossing") } )
1104 Menu( wxT(
"Select"),
XXO(
"&Selection"),
1105 Command( wxT(
"SnapToOff"),
XXO(
"Snap-To &Off"),
FN(OnSnapToOff),
1107 Command( wxT(
"SnapToNearest"),
XXO(
"Snap-To &Nearest"),
1109 Command( wxT(
"SnapToPrior"),
XXO(
"Snap-To &Prior"),
FN(OnSnapToPrior),
1111 Command( wxT(
"SelStart"),
XXO(
"Selection to &Start"),
FN(OnSelToStart),
1113 Command( wxT(
"SelEnd"),
XXO(
"Selection to En&d"),
FN(OnSelToEnd),
1115 Command( wxT(
"SelExtLeft"),
XXO(
"Selection Extend &Left"),
1116 FN(OnSelExtendLeft),
1118 Options{ wxT(
"Shift+Left") }.WantKeyUp().AllowDup() ),
1119 Command( wxT(
"SelExtRight"),
XXO(
"Selection Extend &Right"),
1120 FN(OnSelExtendRight),
1122 Options{ wxT(
"Shift+Right") }.WantKeyUp().AllowDup() ),
1123 Command( wxT(
"SelSetExtLeft"),
XXO(
"Set (or Extend) Le&ft Selection"),
1124 FN(OnSelSetExtendLeft),
1126 Command( wxT(
"SelSetExtRight"),
XXO(
"Set (or Extend) Rig&ht Selection"),
1127 FN(OnSelSetExtendRight),
1129 Command( wxT(
"SelCntrLeft"),
XXO(
"Selection Contract L&eft"),
1130 FN(OnSelContractLeft),
1132 Options{ wxT(
"Ctrl+Shift+Right") }.WantKeyUp() ),
1133 Command( wxT(
"SelCntrRight"),
XXO(
"Selection Contract R&ight"),
1134 FN(OnSelContractRight),
1136 Options{ wxT(
"Ctrl+Shift+Left") }.WantKeyUp() )
1142 wxT(
"Optional/Extra/Part1"),
1160 Menu( wxT(
"Cursor"),
XXO(
"&Cursor to"),
1161 Command( wxT(
"CursSelStart"),
XXO(
"Selection Star&t"),
1162 FN(OnCursorSelStart),
1164 Options{}.LongName(
XO(
"Cursor to Selection Start") ) ),
1165 Command( wxT(
"CursSelEnd"),
XXO(
"Selection En&d"),
1168 Options{}.LongName(
XO(
"Cursor to Selection End") ) ),
1170 Command( wxT(
"CursTrackStart"),
XXO(
"Track &Start"),
1171 FN(OnCursorTrackStart),
1173 Options{ wxT(
"J"),
XO(
"Cursor to Track Start") } ),
1174 Command( wxT(
"CursTrackEnd"),
XXO(
"Track &End"),
1175 FN(OnCursorTrackEnd),
1177 Options{ wxT(
"K"),
XO(
"Cursor to Track End") } ),
1179 Command( wxT(
"CursProjectStart"),
XXO(
"&Project Start"),
1182 Options{ wxT(
"Home"),
XO(
"Cursor to Project Start") } ),
1183 Command( wxT(
"CursProjectEnd"),
XXO(
"Project E&nd"),
FN(OnSkipEnd),
1185 Options{ wxT(
"End"),
XO(
"Cursor to Project End") } )
1191 wxT(
"Transport/Basic"),
1200 Menu( wxT(
"Cursor"),
XXO(
"&Cursor"),
1201 Command( wxT(
"CursorLeft"),
XXO(
"Cursor &Left"),
FN(OnCursorLeft),
1203 Options{ wxT(
"Left") }.WantKeyUp().AllowDup() ),
1204 Command( wxT(
"CursorRight"),
XXO(
"Cursor &Right"),
FN(OnCursorRight),
1206 Options{ wxT(
"Right") }.WantKeyUp().AllowDup() ),
1207 Command( wxT(
"CursorShortJumpLeft"),
XXO(
"Cursor Sh&ort Jump Left"),
1208 FN(OnCursorShortJumpLeft),
1210 Command( wxT(
"CursorShortJumpRight"),
XXO(
"Cursor Shor&t Jump Right"),
1211 FN(OnCursorShortJumpRight),
1213 Command( wxT(
"CursorLongJumpLeft"),
XXO(
"Cursor Long J&ump Left"),
1214 FN(OnCursorLongJumpLeft),
1216 Command( wxT(
"CursorLongJumpRight"),
XXO(
"Cursor Long Ju&mp Right"),
1217 FN(OnCursorLongJumpRight),
1224 wxT(
"Optional/Extra/Part2"),
1233 Menu( wxT(
"Seek"),
XXO(
"See&k"),
1234 Command( wxT(
"SeekLeftShort"),
XXO(
"Short Seek &Left During Playback"),
1236 Options{ wxT(
"Left") }.AllowDup() ),
1237 Command( wxT(
"SeekRightShort"),
1238 XXO(
"Short Seek &Right During Playback"),
FN(OnSeekRightShort),
1240 Options{ wxT(
"Right") }.AllowDup() ),
1241 Command( wxT(
"SeekLeftLong"),
XXO(
"Long Seek Le&ft During Playback"),
1243 Options{ wxT(
"Shift+Left") }.AllowDup() ),
1244 Command( wxT(
"SeekRightLong"),
XXO(
"Long Seek Rig&ht During Playback"),
1246 Options{ wxT(
"Shift+Right") }.AllowDup() )
1252 wxT(
"Optional/Extra/Part1"),
constexpr CommandFlag AlwaysEnabledFlag
wxEvtHandler CommandHandlerObject
const ReservedCommandFlag & AudioIOBusyFlag()
const ReservedCommandFlag & AudioIONotBusyFlag()
const ReservedCommandFlag & IsSyncLockedFlag()
const ReservedCommandFlag & TimeSelectedFlag()
const ReservedCommandFlag & EditableTracksSelectedFlag()
const ReservedCommandFlag & TracksExistFlag()
const ReservedCommandFlag & WaveTracksExistFlag()
const ReservedCommandFlag & WaveTracksSelectedFlag()
const ReservedCommandFlag & TrackPanelHasFocus()
const ReservedCommandFlag & CanStopAudioStreamFlag()
an object holding per-project preferred sample rate
static Settings & settings()
static AdornedRulerPanel & Get(AudacityProject &project)
The top-level handle to an Audacity project. It serves as a source of events that other objects can b...
Client code makes static instance from a factory of attachments; passes it to Get or Find as a retrie...
CommandContext provides additional information to an 'Apply()' command. It provides the project,...
AudacityProject & project
A LabelTrack is a Track that holds labels (LabelStruct).
static LabelTrackView & Get(LabelTrack &)
NumericConverter provides the advanced formatting control used in the selection bar of Audacity.
void SetValue(double newValue)
A listener notified of changes in preferences.
bool IsAudioActive() const
static ProjectAudioIO & Get(AudacityProject &project)
void ModifyState(bool bWantsAutoSave)
static ProjectHistory & Get(AudacityProject &project)
static ProjectRate & Get(AudacityProject &project)
void AS_SetSnapTo(int snap) override
static ProjectSelectionManager & Get(AudacityProject &project)
static ProjectSettings & Get(AudacityProject &project)
static ProjectWindow & Get(AudacityProject &project)
static void SnapCenterOnce(SpectrumAnalyst &analyst, ViewInfo &viewInfo, const WaveTrack *pTrack, bool up)
Defines a selected portion of a project.
static const int UndefinedFrequency
Used for finding the peaks, for snapping to peaks.
static bool IsSyncLockSelected(const Track *pTrack)
virtual bool SupportsBasicEditing() const
Whether this track type implements cut-copy-paste; by default, true.
virtual double GetStartTime() const =0
virtual double GetOffset() const =0
virtual double GetEndTime() const =0
static TrackList & Get(AudacityProject &project)
static TrackPanel & Get(AudacityProject &project)
NotifyingSelectedRegion selectedRegion
static ViewInfo & Get(AudacityProject &project)
A Track that contains audio waveform data.
static WaveTrackView & Get(WaveTrack &track)
std::vector< WaveTrackSubView::Type > GetDisplays() const
auto end(const Ptr< Type, BaseDeleter > &p)
Enables range-for.
std::shared_ptr< BaseItem > BaseItemSharedPtr
void SelectNone(AudacityProject &project)
void DoSelectAll(AudacityProject &project)
void OnSetRegion(AudacityProject &project, bool left, bool selection, const TranslatableString &dialogTitle)
Adjust left or right of selection or play region.
void DoSelectTimeAndTracks(AudacityProject &project, bool bAllTime, bool bAllTracks)
A convenient default parameter for class template Site.
void OnSetLeftSelection(const CommandContext &context)
double mCursorPositionStored
void OnCursorLeft(const CommandContext &context)
void OnSnapToOff(const CommandContext &context)
void OnCursorRight(const CommandContext &context)
Handler & operator=(const Handler &) PROHIBITED
void OnSelExtendRight(const CommandContext &context)
void OnSelectionSave(const CommandContext &context)
void OnSkipEnd(const CommandContext &context)
void OnSelContractRight(const CommandContext &context)
void OnSelContractLeft(const CommandContext &context)
void OnSelectAll(const CommandContext &context)
SelectedRegion mRegionSave
void OnCursorLongJumpRight(const CommandContext &context)
void UpdatePrefs() override
void OnSeekRightShort(const CommandContext &context)
void OnSnapToNearest(const CommandContext &context)
void OnSelToStart(const CommandContext &context)
void OnCursorLongJumpLeft(const CommandContext &context)
void OnSeekLeftShort(const CommandContext &context)
void OnSelectAllTime(const CommandContext &context)
void OnSnapToPrior(const CommandContext &context)
void OnSelectTrackStartToEnd(const CommandContext &context)
void OnCursorTrackEnd(const CommandContext &context)
void OnZeroCrossing(const CommandContext &context)
void OnCursorShortJumpRight(const CommandContext &context)
void OnCursorShortJumpLeft(const CommandContext &context)
void OnCursorTrackStart(const CommandContext &context)
void OnSelectNone(const CommandContext &context)
void OnSelSetExtendLeft(const CommandContext &context)
void OnSelectCursorEnd(const CommandContext &context)
void OnSelectSyncLockSel(const CommandContext &context)
Handler(const Handler &) PROHIBITED
void OnSelectCursorStoredCursor(const CommandContext &context)
void OnSelToEnd(const CommandContext &context)
void OnSelSetExtendRight(const CommandContext &context)
void OnCursorSelStart(const CommandContext &context)
void OnSkipStart(const CommandContext &context)
void OnSelectStartCursor(const CommandContext &context)
void OnSelectionRestore(const CommandContext &context)
void OnSeekRightLong(const CommandContext &context)
void OnSelExtendLeft(const CommandContext &context)
void OnSelectAllTracks(const CommandContext &context)
void OnSetRightSelection(const CommandContext &context)
void OnSeekLeftLong(const CommandContext &context)
void OnCursorPositionStore(const CommandContext &context)
bool mCursorPositionHasBeenStored
void OnCursorSelEnd(const CommandContext &context)