@@ -220,18 +220,31 @@ class NiMidiSurface: public BaseSurface {
220
220
return " Komplete Kontrol S-series Mk2/A-series/M-series" ;
221
221
}
222
222
223
- // ToDo: If the tracklist changes, we always need to call _allMixerUpdate because the change may (or may not) affect the currently visible bank
224
-
225
- // ToDo: Consider using OnTrackSelection() rather than SetSurfaceSelected.
226
- // Reason: SetSurfaceSelected() is less economical because it will be called multiple times (also for unselecting tracks)
227
- // It seems, however, that SetSurfaceSelected() may be the more robust choice because according to other people's
228
- // findings OnTrackSelection() does not work in many situations, e.g. when track is selected via an action! The latter
229
- // is quite common, however, and thus we may have to stick to SetSurfaceSelected().
230
- // See: https://github.com/reaper-oss/sws/blob/6963f7563851c8dd919db426bae825843939077f/sws_extension.cpp#L528
231
- // Remark: The naming of OnTrackSelection() is confusing because typically this would indicate a call from the plugin to
232
- // Reaper to update the project (just like other calls like OnVolumeChange(), OnPlay(), .. etc) .
233
- // When something changes in the project Reaper typically calls functions starting with Set, hence SetTrackSelected()
234
- // seems more logical.
223
+ // If tracklist changes update Mixer View and ensure sanity of track and bank focus
224
+ virtual void SetTrackListChange () override {
225
+ int numTracks = CSurf_NumTracks (false );
226
+ // Protect against loosing track focus that could impede track navigation. Set focus on last track in this case.
227
+ if (g_trackInFocus > numTracks) {
228
+ g_trackInFocus = numTracks;
229
+ // Unfortunately we cannot afford to explicitly select the last track automatically because this could screw up
230
+ // running actions or macros. The plugin may not manipulate track selection without the user deliberately triggering
231
+ // track selection/navigation on the keyboard (or from within Reaper).
232
+ }
233
+ // Protect against loosing bank focus. Set focus on last bank in this case.
234
+ if (this ->_bankStart > numTracks) {
235
+ int lastInBank = numTracks % BANK_NUM_TRACKS;
236
+ this ->_bankStart = numTracks - lastInBank;
237
+ }
238
+ // If no track is selected at all (e.g. if previously selected track got removed), then this will now also show up in the
239
+ // Mixer View. However, KK instance focus may still be present! This can be a little bit confusing for the user as typically
240
+ // the track holding the focused KK instance will also be selected. This situation gets resolved as soon as any form of
241
+ // track navigation/selection happens (from keyboard or from within Reaper).
242
+ this ->_allMixerUpdate ();
243
+ }
244
+
245
+ // Using SetSurfaceSelected() rather than OnTrackSelection():
246
+ // SetSurfaceSelected() is less economical because it will be called multiple times (also for unselecting tracks).
247
+ // However, SetSurfaceSelected() is the more robust choice because of: https://forum.cockos.com/showpost.php?p=2138446&postcount=15
235
248
virtual void SetSurfaceSelected (MediaTrack* track, bool selected) override {
236
249
if (selected) {
237
250
int id = CSurf_TrackToID (track, false );
@@ -496,8 +509,13 @@ class NiMidiSurface: public BaseSurface {
496
509
497
510
void _onTrackNav (signed char value) {
498
511
// Move to next/previous track relative to currently focused track = last selected track
512
+ int numTracks = CSurf_NumTracks (false );
513
+ // Backstop measure to protect against unreported track removal that was not captured in SetTrackListChange callback due to race condition
514
+ if (g_trackInFocus > numTracks) {
515
+ g_trackInFocus = numTracks;
516
+ }
499
517
if (((g_trackInFocus <= 1 ) && (value < 0 )) ||
500
- ((g_trackInFocus >= CSurf_NumTracks ( false ))) && (value >0 )) {
518
+ ((g_trackInFocus >= numTracks) && (value >0 ) )) {
501
519
return ;
502
520
}
503
521
int id = g_trackInFocus + value;
0 commit comments