@coderline/alphatab 1.8.0-alpha.1647 → 1.8.0-alpha.1651
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/alphaTab.core.min.mjs +2 -2
- package/dist/alphaTab.core.mjs +940 -270
- package/dist/alphaTab.d.ts +147 -4
- package/dist/alphaTab.js +940 -270
- package/dist/alphaTab.min.js +2 -2
- package/dist/alphaTab.min.mjs +1 -1
- package/dist/alphaTab.mjs +1 -1
- package/dist/alphaTab.worker.min.mjs +1 -1
- package/dist/alphaTab.worker.mjs +1 -1
- package/dist/alphaTab.worklet.min.mjs +1 -1
- package/dist/alphaTab.worklet.mjs +1 -1
- package/package.json +1 -1
package/dist/alphaTab.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/*!
|
|
2
|
-
* alphaTab v1.8.0-alpha.
|
|
2
|
+
* alphaTab v1.8.0-alpha.1651 (develop, build 1651)
|
|
3
3
|
*
|
|
4
4
|
* Copyright © 2025, Daniel Kuschny and Contributors, All rights reserved.
|
|
5
5
|
*
|
|
@@ -209,9 +209,9 @@
|
|
|
209
209
|
* @internal
|
|
210
210
|
*/
|
|
211
211
|
class VersionInfo {
|
|
212
|
-
static version = '1.8.0-alpha.
|
|
213
|
-
static date = '2025-12-
|
|
214
|
-
static commit = '
|
|
212
|
+
static version = '1.8.0-alpha.1651';
|
|
213
|
+
static date = '2025-12-21T02:27:24.035Z';
|
|
214
|
+
static commit = '758ae890dfa8cdb21a9dd469ade012f834ac0433';
|
|
215
215
|
static print(print) {
|
|
216
216
|
print(`alphaTab ${VersionInfo.version}`);
|
|
217
217
|
print(`commit: ${VersionInfo.commit}`);
|
|
@@ -2750,6 +2750,23 @@
|
|
|
2750
2750
|
* Whether barlines should be drawn across staves within the same system.
|
|
2751
2751
|
*/
|
|
2752
2752
|
extendBarLines = false;
|
|
2753
|
+
/**
|
|
2754
|
+
* Whether to hide empty staves.
|
|
2755
|
+
*/
|
|
2756
|
+
hideEmptyStaves = false;
|
|
2757
|
+
/**
|
|
2758
|
+
* Whether to also hide empty staves in the first system.
|
|
2759
|
+
* @remarks
|
|
2760
|
+
* Only has an effect when activating {@link hideEmptyStaves}.
|
|
2761
|
+
*/
|
|
2762
|
+
hideEmptyStavesInFirstSystem = false;
|
|
2763
|
+
/**
|
|
2764
|
+
* Whether to show brackets and braces across single staves.
|
|
2765
|
+
* @remarks
|
|
2766
|
+
* This allows a more consistent view for identifying staves when using
|
|
2767
|
+
* {@link hideEmptyStaves}
|
|
2768
|
+
*/
|
|
2769
|
+
showSingleStaffBrackets = false;
|
|
2753
2770
|
}
|
|
2754
2771
|
|
|
2755
2772
|
/**
|
|
@@ -8679,7 +8696,10 @@
|
|
|
8679
8696
|
['firstsystemtracknameorientation', [[[[10, 17], 0, ['horizontal', 'vertical']]]]],
|
|
8680
8697
|
['othersystemstracknameorientation', [[[[10, 17], 0, ['horizontal', 'vertical']]]]],
|
|
8681
8698
|
['extendbarlines', null],
|
|
8682
|
-
['chorddiagramsinscore', [[[[10], 1, ['true', 'false']]]]]
|
|
8699
|
+
['chorddiagramsinscore', [[[[10], 1, ['true', 'false']]]]],
|
|
8700
|
+
['hideemptystaves', null],
|
|
8701
|
+
['hideemptystavesinfirstsystem', null],
|
|
8702
|
+
['showsinglestaffbrackets', null]
|
|
8683
8703
|
]);
|
|
8684
8704
|
static staffMetaDataSignatures = AlphaTex1LanguageDefinitions._signatures([
|
|
8685
8705
|
['tuning', [[[[10, 17], 0, ['piano', 'none', 'voice']]], [[[10, 17], 5]]]],
|
|
@@ -9019,6 +9039,9 @@
|
|
|
9019
9039
|
['othersystemstracknameorientation', null],
|
|
9020
9040
|
['extendbarlines', null],
|
|
9021
9041
|
['chorddiagramsinscore', null],
|
|
9042
|
+
['hideemptystaves', null],
|
|
9043
|
+
['hideemptystavesinfirstsystem', null],
|
|
9044
|
+
['showsinglestaffbrackets', null],
|
|
9022
9045
|
[
|
|
9023
9046
|
'tuning',
|
|
9024
9047
|
[
|
|
@@ -13072,7 +13095,7 @@
|
|
|
13072
13095
|
*/
|
|
13073
13096
|
class MasterBarBounds {
|
|
13074
13097
|
/**
|
|
13075
|
-
*
|
|
13098
|
+
* The MasterBar index within the data model represented by these bounds.
|
|
13076
13099
|
*/
|
|
13077
13100
|
index = 0;
|
|
13078
13101
|
/**
|
|
@@ -13280,6 +13303,7 @@
|
|
|
13280
13303
|
mb.visualBounds = this._boundsToJson(masterBar.visualBounds);
|
|
13281
13304
|
mb.realBounds = this._boundsToJson(masterBar.realBounds);
|
|
13282
13305
|
mb.index = masterBar.index;
|
|
13306
|
+
mb.isFirstOfLine = masterBar.isFirstOfLine;
|
|
13283
13307
|
mb.bars = [];
|
|
13284
13308
|
for (const bar of masterBar.bars) {
|
|
13285
13309
|
const b = {};
|
|
@@ -13336,7 +13360,7 @@
|
|
|
13336
13360
|
mb.lineAlignedBounds = BoundsLookup._boundsFromJson(masterBar.lineAlignedBounds);
|
|
13337
13361
|
mb.visualBounds = BoundsLookup._boundsFromJson(masterBar.visualBounds);
|
|
13338
13362
|
mb.realBounds = BoundsLookup._boundsFromJson(masterBar.realBounds);
|
|
13339
|
-
|
|
13363
|
+
lookup.addMasterBar(mb);
|
|
13340
13364
|
for (const bar of masterBar.bars) {
|
|
13341
13365
|
const b = new BarBounds();
|
|
13342
13366
|
b.visualBounds = BoundsLookup._boundsFromJson(bar.visualBounds);
|
|
@@ -13893,6 +13917,15 @@
|
|
|
13893
13917
|
? AlphaTex1LanguageHandler._booleanLikeValue(metaData.arguments.arguments, 0)
|
|
13894
13918
|
: true;
|
|
13895
13919
|
return ApplyNodeResult.Applied;
|
|
13920
|
+
case 'hideemptystaves':
|
|
13921
|
+
score.stylesheet.hideEmptyStaves = true;
|
|
13922
|
+
return ApplyNodeResult.Applied;
|
|
13923
|
+
case 'hideemptystavesinfirstsystem':
|
|
13924
|
+
score.stylesheet.hideEmptyStavesInFirstSystem = true;
|
|
13925
|
+
return ApplyNodeResult.Applied;
|
|
13926
|
+
case 'showsinglestaffbrackets':
|
|
13927
|
+
score.stylesheet.showSingleStaffBrackets = true;
|
|
13928
|
+
return ApplyNodeResult.Applied;
|
|
13896
13929
|
default:
|
|
13897
13930
|
return ApplyNodeResult.NotAppliedUnrecognizedMarker;
|
|
13898
13931
|
}
|
|
@@ -15724,6 +15757,15 @@
|
|
|
15724
15757
|
if (stylesheet.globalDisplayChordDiagramsInScore) {
|
|
15725
15758
|
nodes.push(Atnf.meta('chordDiagramsInScore'));
|
|
15726
15759
|
}
|
|
15760
|
+
if (stylesheet.hideEmptyStaves) {
|
|
15761
|
+
nodes.push(Atnf.meta('hideEmptyStaves'));
|
|
15762
|
+
}
|
|
15763
|
+
if (stylesheet.hideEmptyStavesInFirstSystem) {
|
|
15764
|
+
nodes.push(Atnf.meta('hideEmptyStavesInFirstSystem'));
|
|
15765
|
+
}
|
|
15766
|
+
if (stylesheet.showSingleStaffBrackets) {
|
|
15767
|
+
nodes.push(Atnf.meta('showSingleStaffBrackets'));
|
|
15768
|
+
}
|
|
15727
15769
|
// Unsupported:
|
|
15728
15770
|
// 'globaldisplaychorddiagramsontop',
|
|
15729
15771
|
// 'pertrackchorddiagramsontop',
|
|
@@ -38810,6 +38852,9 @@
|
|
|
38810
38852
|
}
|
|
38811
38853
|
}
|
|
38812
38854
|
o.set("extendbarlines", obj.extendBarLines);
|
|
38855
|
+
o.set("hideemptystaves", obj.hideEmptyStaves);
|
|
38856
|
+
o.set("hideemptystavesinfirstsystem", obj.hideEmptyStavesInFirstSystem);
|
|
38857
|
+
o.set("showsinglestaffbrackets", obj.showSingleStaffBrackets);
|
|
38813
38858
|
return o;
|
|
38814
38859
|
}
|
|
38815
38860
|
static setProperty(obj, property, v) {
|
|
@@ -38871,6 +38916,15 @@
|
|
|
38871
38916
|
case "extendbarlines":
|
|
38872
38917
|
obj.extendBarLines = v;
|
|
38873
38918
|
return true;
|
|
38919
|
+
case "hideemptystaves":
|
|
38920
|
+
obj.hideEmptyStaves = v;
|
|
38921
|
+
return true;
|
|
38922
|
+
case "hideemptystavesinfirstsystem":
|
|
38923
|
+
obj.hideEmptyStavesInFirstSystem = v;
|
|
38924
|
+
return true;
|
|
38925
|
+
case "showsinglestaffbrackets":
|
|
38926
|
+
obj.showSingleStaffBrackets = v;
|
|
38927
|
+
return true;
|
|
38874
38928
|
}
|
|
38875
38929
|
return false;
|
|
38876
38930
|
}
|
|
@@ -43610,6 +43664,12 @@
|
|
|
43610
43664
|
* Scrolling happens as soon the cursors exceed the displayed range.
|
|
43611
43665
|
*/
|
|
43612
43666
|
ScrollMode[ScrollMode["OffScreen"] = 2] = "OffScreen";
|
|
43667
|
+
/**
|
|
43668
|
+
* Scrolling happens constantly in a smooth fashion.
|
|
43669
|
+
* This will disable the use of any native scroll optimizations but
|
|
43670
|
+
* manually scroll the scroll container in the required speed.
|
|
43671
|
+
*/
|
|
43672
|
+
ScrollMode[ScrollMode["Smooth"] = 3] = "Smooth";
|
|
43613
43673
|
})(exports.ScrollMode || (exports.ScrollMode = {}));
|
|
43614
43674
|
/**
|
|
43615
43675
|
* This object defines the details on how to generate the vibrato effects.
|
|
@@ -45898,6 +45958,19 @@
|
|
|
45898
45958
|
}
|
|
45899
45959
|
return null;
|
|
45900
45960
|
}
|
|
45961
|
+
/**
|
|
45962
|
+
* Looks for the first visible beat which starts at this lookup so it can be used for cursor placement.
|
|
45963
|
+
* @param checker The custom checker to see if a beat is visible.
|
|
45964
|
+
* @returns The first beat which is visible according to the given tracks or null.
|
|
45965
|
+
*/
|
|
45966
|
+
getVisibleBeatAtStartWithChecker(checker) {
|
|
45967
|
+
for (const b of this.highlightedBeats) {
|
|
45968
|
+
if (b.playbackStart === this.start && checker.isVisible(b.beat)) {
|
|
45969
|
+
return b.beat;
|
|
45970
|
+
}
|
|
45971
|
+
}
|
|
45972
|
+
return null;
|
|
45973
|
+
}
|
|
45901
45974
|
}
|
|
45902
45975
|
|
|
45903
45976
|
/**
|
|
@@ -46337,6 +46410,18 @@
|
|
|
46337
46410
|
}
|
|
46338
46411
|
}
|
|
46339
46412
|
}
|
|
46413
|
+
/**
|
|
46414
|
+
* @internal
|
|
46415
|
+
*/
|
|
46416
|
+
class TrackLookupBeatVisibilityChecker {
|
|
46417
|
+
_lookup;
|
|
46418
|
+
constructor(lookup) {
|
|
46419
|
+
this._lookup = lookup;
|
|
46420
|
+
}
|
|
46421
|
+
isVisible(beat) {
|
|
46422
|
+
return this._lookup.has(beat.voice.bar.staff.track.index);
|
|
46423
|
+
}
|
|
46424
|
+
}
|
|
46340
46425
|
/**
|
|
46341
46426
|
* This class holds all information about when {@link MasterBar}s and {@link Beat}s are played.
|
|
46342
46427
|
*
|
|
@@ -46397,31 +46482,44 @@
|
|
|
46397
46482
|
* @returns The information about the current beat or null if no beat could be found.
|
|
46398
46483
|
*/
|
|
46399
46484
|
findBeat(trackLookup, tick, currentBeatHint = null) {
|
|
46485
|
+
return this.findBeatWithChecker(new TrackLookupBeatVisibilityChecker(trackLookup), tick, currentBeatHint);
|
|
46486
|
+
}
|
|
46487
|
+
/**
|
|
46488
|
+
* Finds the currently played beat given a list of tracks and the current time.
|
|
46489
|
+
* @param checker The checker to ask whether a beat is visible and should be considered for result.
|
|
46490
|
+
* @param tick The current time in midi ticks.
|
|
46491
|
+
* @param currentBeatHint Used for optimized lookup during playback. By passing in a previous result lookup of the next one can be optimized using heuristics. (optional).
|
|
46492
|
+
* @returns The information about the current beat or null if no beat could be found.
|
|
46493
|
+
*/
|
|
46494
|
+
findBeatWithChecker(checker, tick, currentBeatHint = null) {
|
|
46400
46495
|
let result = null;
|
|
46401
46496
|
if (currentBeatHint) {
|
|
46402
|
-
result = this._findBeatFast(
|
|
46497
|
+
result = this._findBeatFast(checker, currentBeatHint, tick);
|
|
46403
46498
|
}
|
|
46404
46499
|
if (!result) {
|
|
46405
|
-
result = this._findBeatSlow(
|
|
46500
|
+
result = this._findBeatSlow(checker, currentBeatHint, tick, false);
|
|
46406
46501
|
}
|
|
46407
46502
|
return result;
|
|
46408
46503
|
}
|
|
46409
|
-
_findBeatFast(
|
|
46504
|
+
_findBeatFast(checker, currentBeatHint, tick) {
|
|
46410
46505
|
// still within current lookup.
|
|
46411
46506
|
if (tick >= currentBeatHint.start && tick < currentBeatHint.end) {
|
|
46412
46507
|
return currentBeatHint;
|
|
46413
46508
|
}
|
|
46414
46509
|
// already on the next beat?
|
|
46415
|
-
if (currentBeatHint.nextBeat &&
|
|
46510
|
+
if (currentBeatHint.nextBeat &&
|
|
46511
|
+
tick >= currentBeatHint.nextBeat.start &&
|
|
46512
|
+
tick < currentBeatHint.nextBeat.end &&
|
|
46513
|
+
(checker === undefined || checker.isVisible(currentBeatHint.nextBeat.beat))) {
|
|
46416
46514
|
const next = currentBeatHint.nextBeat;
|
|
46417
46515
|
// fill next in chain
|
|
46418
|
-
this._fillNextBeat(next,
|
|
46516
|
+
this._fillNextBeat(next, checker);
|
|
46419
46517
|
return next;
|
|
46420
46518
|
}
|
|
46421
46519
|
// likely a loop or manual seek, need to fallback to slow path
|
|
46422
46520
|
return null;
|
|
46423
46521
|
}
|
|
46424
|
-
_fillNextBeatMultiBarRest(current,
|
|
46522
|
+
_fillNextBeatMultiBarRest(current, checker) {
|
|
46425
46523
|
const group = this.multiBarRestInfo.get(current.masterBar.masterBar.index);
|
|
46426
46524
|
// this is a bit sensitive. we assume that the sequence of multi-rest bars and the
|
|
46427
46525
|
// chained nextMasterBar equal. so we just jump over X bars
|
|
@@ -46435,7 +46533,7 @@
|
|
|
46435
46533
|
if (endMasterBar) {
|
|
46436
46534
|
// one more following -> use start of next
|
|
46437
46535
|
if (endMasterBar.nextMasterBar) {
|
|
46438
|
-
current.nextBeat = this._firstBeatInMasterBar(
|
|
46536
|
+
current.nextBeat = this._firstBeatInMasterBar(checker, endMasterBar.nextMasterBar, endMasterBar.nextMasterBar.start, true);
|
|
46439
46537
|
// if we have the next beat take the difference between the times as duration
|
|
46440
46538
|
if (current.nextBeat) {
|
|
46441
46539
|
current.tickDuration = current.nextBeat.start - current.start;
|
|
@@ -46465,19 +46563,19 @@
|
|
|
46465
46563
|
}
|
|
46466
46564
|
current.calculateDuration();
|
|
46467
46565
|
}
|
|
46468
|
-
_fillNextBeat(current,
|
|
46566
|
+
_fillNextBeat(current, checker) {
|
|
46469
46567
|
// on multibar rests take the duration until the end.
|
|
46470
46568
|
if (this._isMultiBarRestResult(current)) {
|
|
46471
|
-
this._fillNextBeatMultiBarRest(current,
|
|
46569
|
+
this._fillNextBeatMultiBarRest(current, checker);
|
|
46472
46570
|
}
|
|
46473
46571
|
else {
|
|
46474
|
-
this._fillNextBeatDefault(current,
|
|
46572
|
+
this._fillNextBeatDefault(current, checker);
|
|
46475
46573
|
}
|
|
46476
46574
|
}
|
|
46477
|
-
_fillNextBeatDefault(current,
|
|
46478
|
-
current.nextBeat = this._findBeatInMasterBar(current.masterBar, current.beatLookup.nextBeat, current.end,
|
|
46575
|
+
_fillNextBeatDefault(current, checker) {
|
|
46576
|
+
current.nextBeat = this._findBeatInMasterBar(current.masterBar, current.beatLookup.nextBeat, current.end, checker, true);
|
|
46479
46577
|
if (current.nextBeat == null) {
|
|
46480
|
-
current.nextBeat = this._findBeatSlow(
|
|
46578
|
+
current.nextBeat = this._findBeatSlow(checker, current, current.end, true);
|
|
46481
46579
|
}
|
|
46482
46580
|
// if we have the next beat take the difference between the times as duration
|
|
46483
46581
|
if (current.nextBeat) {
|
|
@@ -46508,7 +46606,7 @@
|
|
|
46508
46606
|
beat.isRest &&
|
|
46509
46607
|
beat.voice.bar.isRestOnly);
|
|
46510
46608
|
}
|
|
46511
|
-
_findBeatSlow(
|
|
46609
|
+
_findBeatSlow(checker, currentBeatHint, tick, isNextSearch) {
|
|
46512
46610
|
// get all beats within the masterbar
|
|
46513
46611
|
let masterBar = null;
|
|
46514
46612
|
if (currentBeatHint != null) {
|
|
@@ -46530,14 +46628,14 @@
|
|
|
46530
46628
|
if (!masterBar) {
|
|
46531
46629
|
return null;
|
|
46532
46630
|
}
|
|
46533
|
-
return this._firstBeatInMasterBar(
|
|
46631
|
+
return this._firstBeatInMasterBar(checker, masterBar, tick, isNextSearch);
|
|
46534
46632
|
}
|
|
46535
|
-
_firstBeatInMasterBar(
|
|
46633
|
+
_firstBeatInMasterBar(checker, startMasterBar, tick, isNextSearch) {
|
|
46536
46634
|
let masterBar = startMasterBar;
|
|
46537
46635
|
// scan through beats and find first one which has a beat visible
|
|
46538
46636
|
while (masterBar) {
|
|
46539
46637
|
if (masterBar.firstBeat) {
|
|
46540
|
-
const beat = this._findBeatInMasterBar(masterBar, masterBar.firstBeat, tick,
|
|
46638
|
+
const beat = this._findBeatInMasterBar(masterBar, masterBar.firstBeat, tick, checker, isNextSearch);
|
|
46541
46639
|
if (beat) {
|
|
46542
46640
|
return beat;
|
|
46543
46641
|
}
|
|
@@ -46555,7 +46653,7 @@
|
|
|
46555
46653
|
* @param isNextSearch
|
|
46556
46654
|
* @returns
|
|
46557
46655
|
*/
|
|
46558
|
-
_findBeatInMasterBar(masterBar, currentStartLookup, tick,
|
|
46656
|
+
_findBeatInMasterBar(masterBar, currentStartLookup, tick, checker, isNextSearch) {
|
|
46559
46657
|
if (!currentStartLookup) {
|
|
46560
46658
|
return null;
|
|
46561
46659
|
}
|
|
@@ -46569,7 +46667,7 @@
|
|
|
46569
46667
|
(currentStartLookup.start <= relativeTick || (isNextSearch && relativeTick < 0)) &&
|
|
46570
46668
|
relativeTick < currentStartLookup.end) {
|
|
46571
46669
|
startBeatLookup = currentStartLookup;
|
|
46572
|
-
startBeat = currentStartLookup.
|
|
46670
|
+
startBeat = currentStartLookup.getVisibleBeatAtStartWithChecker(checker);
|
|
46573
46671
|
// found the matching beat lookup but none of the beats are visible
|
|
46574
46672
|
// in this case scan further to the next lookup which has any visible beat
|
|
46575
46673
|
if (!startBeat) {
|
|
@@ -46577,7 +46675,7 @@
|
|
|
46577
46675
|
let currentMasterBar = masterBar;
|
|
46578
46676
|
while (currentMasterBar != null && startBeat == null) {
|
|
46579
46677
|
while (currentStartLookup != null) {
|
|
46580
|
-
startBeat = currentStartLookup.
|
|
46678
|
+
startBeat = currentStartLookup.getVisibleBeatAtStartWithChecker(checker);
|
|
46581
46679
|
if (startBeat) {
|
|
46582
46680
|
startBeatLookup = currentStartLookup;
|
|
46583
46681
|
masterBar = currentMasterBar;
|
|
@@ -46595,7 +46693,7 @@
|
|
|
46595
46693
|
let currentMasterBar = masterBar;
|
|
46596
46694
|
while (currentMasterBar != null && startBeat == null) {
|
|
46597
46695
|
while (currentStartLookup != null) {
|
|
46598
|
-
startBeat = currentStartLookup.
|
|
46696
|
+
startBeat = currentStartLookup.getVisibleBeatAtStartWithChecker(checker);
|
|
46599
46697
|
if (startBeat) {
|
|
46600
46698
|
startBeatLookup = currentStartLookup;
|
|
46601
46699
|
masterBar = currentMasterBar;
|
|
@@ -46619,17 +46717,17 @@
|
|
|
46619
46717
|
if (startBeat == null) {
|
|
46620
46718
|
return null;
|
|
46621
46719
|
}
|
|
46622
|
-
const result = this._createResult(masterBar, startBeatLookup, startBeat, isNextSearch,
|
|
46720
|
+
const result = this._createResult(masterBar, startBeatLookup, startBeat, isNextSearch, checker);
|
|
46623
46721
|
return result;
|
|
46624
46722
|
}
|
|
46625
|
-
_createResult(masterBar, beatLookup, beat, isNextSearch,
|
|
46723
|
+
_createResult(masterBar, beatLookup, beat, isNextSearch, checker) {
|
|
46626
46724
|
const result = new MidiTickLookupFindBeatResult(masterBar);
|
|
46627
46725
|
result.beat = beat;
|
|
46628
46726
|
result.beatLookup = beatLookup;
|
|
46629
46727
|
result.tickDuration = beatLookup.end - beatLookup.start;
|
|
46630
46728
|
if (!isNextSearch) {
|
|
46631
46729
|
// the next beat filling will adjust this result with the respective durations
|
|
46632
|
-
this._fillNextBeat(result,
|
|
46730
|
+
this._fillNextBeat(result, checker);
|
|
46633
46731
|
}
|
|
46634
46732
|
else if (this._isMultiBarRestResult(result)) {
|
|
46635
46733
|
const multiRest = this.multiBarRestInfo.get(masterBar.masterBar.index);
|
|
@@ -48502,6 +48600,25 @@
|
|
|
48502
48600
|
}
|
|
48503
48601
|
}
|
|
48504
48602
|
|
|
48603
|
+
/**
|
|
48604
|
+
* Represents the information related to a resize event.
|
|
48605
|
+
* @public
|
|
48606
|
+
*/
|
|
48607
|
+
class ResizeEventArgs {
|
|
48608
|
+
/**
|
|
48609
|
+
* Gets the size before the resizing happened.
|
|
48610
|
+
*/
|
|
48611
|
+
oldWidth = 0;
|
|
48612
|
+
/**
|
|
48613
|
+
* Gets the size after the resize was complete.
|
|
48614
|
+
*/
|
|
48615
|
+
newWidth = 0;
|
|
48616
|
+
/**
|
|
48617
|
+
* Gets the settings currently used for rendering.
|
|
48618
|
+
*/
|
|
48619
|
+
settings = null;
|
|
48620
|
+
}
|
|
48621
|
+
|
|
48505
48622
|
/**
|
|
48506
48623
|
* Lists the different position modes for {@link BarRendererBase.getBeatX}
|
|
48507
48624
|
* @internal
|
|
@@ -48928,22 +49045,262 @@
|
|
|
48928
49045
|
}
|
|
48929
49046
|
|
|
48930
49047
|
/**
|
|
48931
|
-
*
|
|
48932
|
-
* @
|
|
49048
|
+
* Some basic scroll handler checking for changed offsets and scroll if changed.
|
|
49049
|
+
* @internal
|
|
48933
49050
|
*/
|
|
48934
|
-
class
|
|
48935
|
-
|
|
48936
|
-
|
|
48937
|
-
|
|
48938
|
-
|
|
48939
|
-
|
|
48940
|
-
|
|
48941
|
-
|
|
48942
|
-
|
|
48943
|
-
|
|
48944
|
-
|
|
48945
|
-
|
|
48946
|
-
|
|
49051
|
+
class BasicScrollHandler {
|
|
49052
|
+
api;
|
|
49053
|
+
lastScroll = -1;
|
|
49054
|
+
constructor(api) {
|
|
49055
|
+
this.api = api;
|
|
49056
|
+
}
|
|
49057
|
+
[Symbol.dispose]() {
|
|
49058
|
+
}
|
|
49059
|
+
forceScrollTo(currentBeatBounds) {
|
|
49060
|
+
this._scrollToBeat(currentBeatBounds, true);
|
|
49061
|
+
this.lastScroll = -1; // force new scroll on next update
|
|
49062
|
+
}
|
|
49063
|
+
_scrollToBeat(currentBeatBounds, force) {
|
|
49064
|
+
const newLastScroll = this.calculateLastScroll(currentBeatBounds);
|
|
49065
|
+
// no change, and no instant/force scroll
|
|
49066
|
+
if (newLastScroll === this.lastScroll && !force) {
|
|
49067
|
+
return;
|
|
49068
|
+
}
|
|
49069
|
+
this.lastScroll = newLastScroll;
|
|
49070
|
+
this.doScroll(currentBeatBounds);
|
|
49071
|
+
}
|
|
49072
|
+
onBeatCursorUpdating(startBeat, _endBeat, _cursorMode, _actualBeatCursorStartX, _actualBeatCursorEndX, _actualBeatCursorTransitionDuration) {
|
|
49073
|
+
this._scrollToBeat(startBeat, false);
|
|
49074
|
+
}
|
|
49075
|
+
}
|
|
49076
|
+
/**
|
|
49077
|
+
* This is the default scroll handler for vertical layouts using {@link ScrollMode.Continuous}.
|
|
49078
|
+
* Whenever the system changes, we scroll to the new system position vertically.
|
|
49079
|
+
* @internal
|
|
49080
|
+
*/
|
|
49081
|
+
class VerticalContinuousScrollHandler extends BasicScrollHandler {
|
|
49082
|
+
calculateLastScroll(currentBeatBounds) {
|
|
49083
|
+
return currentBeatBounds.barBounds.masterBarBounds.realBounds.y;
|
|
49084
|
+
}
|
|
49085
|
+
doScroll(currentBeatBounds) {
|
|
49086
|
+
const ui = this.api.uiFacade;
|
|
49087
|
+
const settings = this.api.settings;
|
|
49088
|
+
const scroll = ui.getScrollContainer();
|
|
49089
|
+
const elementOffset = ui.getOffset(scroll, this.api.container);
|
|
49090
|
+
const y = currentBeatBounds.barBounds.masterBarBounds.realBounds.y + settings.player.scrollOffsetY;
|
|
49091
|
+
ui.scrollToY(scroll, elementOffset.y + y, this.api.settings.player.scrollSpeed);
|
|
49092
|
+
}
|
|
49093
|
+
}
|
|
49094
|
+
/**
|
|
49095
|
+
* This is the default scroll handler for vertical layouts using {@link ScrollMode.OffScreen}.
|
|
49096
|
+
* Whenever the system changes, we check if the new system bounds are out-of-screen and if yes, we scroll.
|
|
49097
|
+
* @internal
|
|
49098
|
+
*/
|
|
49099
|
+
class VerticalOffScreenScrollHandler extends BasicScrollHandler {
|
|
49100
|
+
calculateLastScroll(currentBeatBounds) {
|
|
49101
|
+
// check for system change
|
|
49102
|
+
return currentBeatBounds.barBounds.masterBarBounds.realBounds.y;
|
|
49103
|
+
}
|
|
49104
|
+
doScroll(currentBeatBounds) {
|
|
49105
|
+
const ui = this.api.uiFacade;
|
|
49106
|
+
const settings = this.api.settings;
|
|
49107
|
+
const scroll = ui.getScrollContainer();
|
|
49108
|
+
const elementBottom = scroll.scrollTop + ui.getOffset(null, scroll).h;
|
|
49109
|
+
const barBoundings = currentBeatBounds.barBounds.masterBarBounds;
|
|
49110
|
+
if (barBoundings.visualBounds.y + barBoundings.visualBounds.h >= elementBottom ||
|
|
49111
|
+
barBoundings.visualBounds.y < scroll.scrollTop) {
|
|
49112
|
+
const scrollTop = barBoundings.realBounds.y + settings.player.scrollOffsetY;
|
|
49113
|
+
ui.scrollToY(scroll, scrollTop, settings.player.scrollSpeed);
|
|
49114
|
+
}
|
|
49115
|
+
}
|
|
49116
|
+
}
|
|
49117
|
+
/**
|
|
49118
|
+
* This is the default scroll handler for vertical layouts using {@link ScrollMode.Smooth}.
|
|
49119
|
+
* vertical smooth scrolling aims to place the on-time position
|
|
49120
|
+
* at scrollOffsetY **at the time when a system starts**
|
|
49121
|
+
* this means when a system starts, it is at scrollOffsetY,
|
|
49122
|
+
* then gradually scrolls down the system height reaching the bottom
|
|
49123
|
+
* when the system completes.
|
|
49124
|
+
* @internal
|
|
49125
|
+
*/
|
|
49126
|
+
class VerticalSmoothScrollHandler {
|
|
49127
|
+
_api;
|
|
49128
|
+
_lastScroll = -1;
|
|
49129
|
+
_scrollContainerResizeUnregister;
|
|
49130
|
+
constructor(api) {
|
|
49131
|
+
this._api = api;
|
|
49132
|
+
// we need a resize listener for the overflow calculation
|
|
49133
|
+
this._scrollContainerResizeUnregister = api.uiFacade.getScrollContainer().resize.on(() => {
|
|
49134
|
+
const scrollContainer = api.uiFacade.getScrollContainer();
|
|
49135
|
+
const overflowNeeded = api.settings.player.scrollOffsetX;
|
|
49136
|
+
const viewPortSize = scrollContainer.width;
|
|
49137
|
+
// the content needs to shift out of screen (and back into screen with the offset)
|
|
49138
|
+
// that's why we need the whole width as additional overflow
|
|
49139
|
+
const overflowNeededAbsolute = viewPortSize + overflowNeeded;
|
|
49140
|
+
api.uiFacade.setCanvasOverflow(api.canvasElement, overflowNeededAbsolute, true);
|
|
49141
|
+
});
|
|
49142
|
+
}
|
|
49143
|
+
[Symbol.dispose]() {
|
|
49144
|
+
this._api.uiFacade.setCanvasOverflow(this._api.canvasElement, 0, true);
|
|
49145
|
+
this._scrollContainerResizeUnregister();
|
|
49146
|
+
}
|
|
49147
|
+
forceScrollTo(currentBeatBounds) {
|
|
49148
|
+
const ui = this._api.uiFacade;
|
|
49149
|
+
const settings = this._api.settings;
|
|
49150
|
+
const scroll = ui.getScrollContainer();
|
|
49151
|
+
const systemTop = currentBeatBounds.barBounds.masterBarBounds.realBounds.y + settings.player.scrollOffsetY;
|
|
49152
|
+
ui.scrollToY(scroll, systemTop, 0);
|
|
49153
|
+
this._lastScroll = -1;
|
|
49154
|
+
}
|
|
49155
|
+
onBeatCursorUpdating(startBeat, _endBeat, _cursorMode, _actualBeatCursorStartX, _actualBeatCursorEndX, actualBeatCursorTransitionDuration) {
|
|
49156
|
+
const ui = this._api.uiFacade;
|
|
49157
|
+
const settings = this._api.settings;
|
|
49158
|
+
const barBoundings = startBeat.barBounds.masterBarBounds;
|
|
49159
|
+
const systemTop = barBoundings.realBounds.y + settings.player.scrollOffsetY;
|
|
49160
|
+
if (systemTop === this._lastScroll && actualBeatCursorTransitionDuration > 0) {
|
|
49161
|
+
return;
|
|
49162
|
+
}
|
|
49163
|
+
// jump to start of new system
|
|
49164
|
+
const scroll = ui.getScrollContainer();
|
|
49165
|
+
ui.scrollToY(scroll, systemTop, 0);
|
|
49166
|
+
// instant scroll
|
|
49167
|
+
if (actualBeatCursorTransitionDuration === 0) {
|
|
49168
|
+
this._lastScroll = -1;
|
|
49169
|
+
return;
|
|
49170
|
+
}
|
|
49171
|
+
// dynamic scrolling
|
|
49172
|
+
this._lastScroll = systemTop;
|
|
49173
|
+
// scroll to bottom over time
|
|
49174
|
+
const systemBottom = systemTop + barBoundings.realBounds.h;
|
|
49175
|
+
// NOTE: this calculation is a bit more expensive, but we only do it once per system
|
|
49176
|
+
// so we should be good:
|
|
49177
|
+
// * the more bars we have, the longer the system will play, hence the duration can take a bit longer
|
|
49178
|
+
// * if we have less bars, we calculate more often, but the calculation will be faster because we sum up less bars.
|
|
49179
|
+
const systemDuration = this._calculateSystemDuration(barBoundings);
|
|
49180
|
+
ui.scrollToY(scroll, systemBottom, systemDuration);
|
|
49181
|
+
}
|
|
49182
|
+
_calculateSystemDuration(barBoundings) {
|
|
49183
|
+
const systemBars = barBoundings.staffSystemBounds.bars;
|
|
49184
|
+
const tickCache = this._api.tickCache;
|
|
49185
|
+
let duration = 0;
|
|
49186
|
+
const masterBars = this._api.score.masterBars;
|
|
49187
|
+
for (const bar of systemBars) {
|
|
49188
|
+
const mb = masterBars[bar.index];
|
|
49189
|
+
const mbInfo = tickCache.getMasterBar(mb);
|
|
49190
|
+
const tempoChanges = tickCache.getMasterBar(mb).tempoChanges;
|
|
49191
|
+
let tempo = tempoChanges[0].tempo;
|
|
49192
|
+
let tick = tempoChanges[0].tick;
|
|
49193
|
+
for (let i = 1; i < tempoChanges.length; i++) {
|
|
49194
|
+
const diff = tempoChanges[i].tick - tick;
|
|
49195
|
+
duration += MidiUtils.ticksToMillis(diff, tempo);
|
|
49196
|
+
tempo = tempoChanges[i].tempo;
|
|
49197
|
+
tick = tempoChanges[i].tick;
|
|
49198
|
+
}
|
|
49199
|
+
const toEnd = mbInfo.end - tick;
|
|
49200
|
+
duration += MidiUtils.ticksToMillis(toEnd, tempo);
|
|
49201
|
+
}
|
|
49202
|
+
return duration;
|
|
49203
|
+
}
|
|
49204
|
+
}
|
|
49205
|
+
/**
|
|
49206
|
+
* This is the default scroll handler for horizontal layouts using {@link ScrollMode.Continuous}.
|
|
49207
|
+
* Whenever the master bar changes, we scroll to the position horizontally.
|
|
49208
|
+
* @internal
|
|
49209
|
+
*/
|
|
49210
|
+
class HorizontalContinuousScrollHandler extends BasicScrollHandler {
|
|
49211
|
+
calculateLastScroll(currentBeatBounds) {
|
|
49212
|
+
return currentBeatBounds.barBounds.masterBarBounds.visualBounds.x;
|
|
49213
|
+
}
|
|
49214
|
+
doScroll(currentBeatBounds) {
|
|
49215
|
+
const ui = this.api.uiFacade;
|
|
49216
|
+
const settings = this.api.settings;
|
|
49217
|
+
const scroll = ui.getScrollContainer();
|
|
49218
|
+
const barBoundings = currentBeatBounds.barBounds.masterBarBounds;
|
|
49219
|
+
const scrollLeftContinuous = barBoundings.realBounds.x + settings.player.scrollOffsetX;
|
|
49220
|
+
ui.scrollToX(scroll, scrollLeftContinuous, settings.player.scrollSpeed);
|
|
49221
|
+
}
|
|
49222
|
+
}
|
|
49223
|
+
/**
|
|
49224
|
+
* This is the default scroll handler for horizontal layouts using {@link ScrollMode.OffScreen}.
|
|
49225
|
+
* Whenever the system changes, we check if the new system bounds are out-of-screen and if yes, we scroll.
|
|
49226
|
+
* @internal
|
|
49227
|
+
*/
|
|
49228
|
+
class HorizontalOffScreenScrollHandler extends BasicScrollHandler {
|
|
49229
|
+
calculateLastScroll(currentBeatBounds) {
|
|
49230
|
+
return currentBeatBounds.barBounds.masterBarBounds.visualBounds.x;
|
|
49231
|
+
}
|
|
49232
|
+
doScroll(currentBeatBounds) {
|
|
49233
|
+
const ui = this.api.uiFacade;
|
|
49234
|
+
const settings = this.api.settings;
|
|
49235
|
+
const scroll = ui.getScrollContainer();
|
|
49236
|
+
const elementRight = scroll.scrollLeft + ui.getOffset(null, scroll).w;
|
|
49237
|
+
const barBoundings = currentBeatBounds.barBounds.masterBarBounds;
|
|
49238
|
+
if (barBoundings.visualBounds.x + barBoundings.visualBounds.w >= elementRight ||
|
|
49239
|
+
barBoundings.visualBounds.x < scroll.scrollLeft) {
|
|
49240
|
+
const scrollLeftOffScreen = barBoundings.realBounds.x + settings.player.scrollOffsetX;
|
|
49241
|
+
ui.scrollToX(scroll, scrollLeftOffScreen, settings.player.scrollSpeed);
|
|
49242
|
+
}
|
|
49243
|
+
}
|
|
49244
|
+
}
|
|
49245
|
+
/**
|
|
49246
|
+
* This is the default scroll handler for horizontal layouts using {@link ScrollMode.Smooth}.
|
|
49247
|
+
* horiontal smooth scrolling aims to place the on-time position
|
|
49248
|
+
* at scrollOffsetX from a beat-to-beat perspective.
|
|
49249
|
+
* This achieves an steady cursor at the same position with rather the music sheet scrolling past it.
|
|
49250
|
+
* Due to some animation inconsistencies (e.g. CSS animation vs scrolling) there might be a slight
|
|
49251
|
+
* flickering of the cursor.
|
|
49252
|
+
*
|
|
49253
|
+
* To get a fully steady cursor the beat cursor can simply be visually hidden and a cursor can be placed at
|
|
49254
|
+
* `scrollOffsetX` by the integrator.
|
|
49255
|
+
* @internal
|
|
49256
|
+
*/
|
|
49257
|
+
class HorizontalSmoothScrollHandler {
|
|
49258
|
+
_api;
|
|
49259
|
+
_lastScroll = -1;
|
|
49260
|
+
_scrollContainerResizeUnregister;
|
|
49261
|
+
constructor(api) {
|
|
49262
|
+
this._api = api;
|
|
49263
|
+
// we need a resize listener for the overflow calculation
|
|
49264
|
+
this._scrollContainerResizeUnregister = api.uiFacade.getScrollContainer().resize.on(() => {
|
|
49265
|
+
const scrollContainer = api.uiFacade.getScrollContainer();
|
|
49266
|
+
const overflowNeeded = api.settings.player.scrollOffsetX;
|
|
49267
|
+
const viewPortSize = scrollContainer.width;
|
|
49268
|
+
// the content needs to shift out of screen (and back into screen with the offset)
|
|
49269
|
+
// that's why we need the whole width as additional overflow
|
|
49270
|
+
const overflowNeededAbsolute = viewPortSize + overflowNeeded;
|
|
49271
|
+
api.uiFacade.setCanvasOverflow(api.canvasElement, overflowNeededAbsolute, false);
|
|
49272
|
+
});
|
|
49273
|
+
}
|
|
49274
|
+
[Symbol.dispose]() {
|
|
49275
|
+
this._scrollContainerResizeUnregister();
|
|
49276
|
+
this._api.uiFacade.setCanvasOverflow(this._api.canvasElement, 0, false);
|
|
49277
|
+
}
|
|
49278
|
+
forceScrollTo(currentBeatBounds) {
|
|
49279
|
+
const ui = this._api.uiFacade;
|
|
49280
|
+
const settings = this._api.settings;
|
|
49281
|
+
const scroll = ui.getScrollContainer();
|
|
49282
|
+
const barStartX = currentBeatBounds.onNotesX + settings.player.scrollOffsetY;
|
|
49283
|
+
ui.scrollToY(scroll, barStartX, 0);
|
|
49284
|
+
this._lastScroll = -1;
|
|
49285
|
+
}
|
|
49286
|
+
onBeatCursorUpdating(_startBeat, _endBeat, _cursorMode, actualBeatCursorStartX, actualBeatCursorEndX, actualBeatCursorTransitionDuration) {
|
|
49287
|
+
const ui = this._api.uiFacade;
|
|
49288
|
+
if (actualBeatCursorEndX === this._lastScroll && actualBeatCursorTransitionDuration > 0) {
|
|
49289
|
+
return;
|
|
49290
|
+
}
|
|
49291
|
+
// jump to start of new system
|
|
49292
|
+
const settings = this._api.settings;
|
|
49293
|
+
const scroll = ui.getScrollContainer();
|
|
49294
|
+
ui.scrollToX(scroll, actualBeatCursorStartX + settings.player.scrollOffsetX, 0);
|
|
49295
|
+
// instant scroll
|
|
49296
|
+
if (actualBeatCursorTransitionDuration === 0) {
|
|
49297
|
+
this._lastScroll = -1;
|
|
49298
|
+
return;
|
|
49299
|
+
}
|
|
49300
|
+
this._lastScroll = actualBeatCursorEndX;
|
|
49301
|
+
const scrollX = actualBeatCursorEndX + settings.player.scrollOffsetX;
|
|
49302
|
+
ui.scrollToX(scroll, scrollX, actualBeatCursorTransitionDuration);
|
|
49303
|
+
}
|
|
48947
49304
|
}
|
|
48948
49305
|
|
|
48949
49306
|
/**
|
|
@@ -49556,6 +49913,19 @@
|
|
|
49556
49913
|
}
|
|
49557
49914
|
}
|
|
49558
49915
|
|
|
49916
|
+
/**
|
|
49917
|
+
* @internal
|
|
49918
|
+
*/
|
|
49919
|
+
class BoundsLookupVisibilityChecker {
|
|
49920
|
+
bounds = null;
|
|
49921
|
+
isVisible(beat) {
|
|
49922
|
+
const bounds = this.bounds;
|
|
49923
|
+
if (!bounds) {
|
|
49924
|
+
return false;
|
|
49925
|
+
}
|
|
49926
|
+
return bounds.findBeat(beat) !== null;
|
|
49927
|
+
}
|
|
49928
|
+
}
|
|
49559
49929
|
/**
|
|
49560
49930
|
* This class represents the public API of alphaTab and provides all logic to display
|
|
49561
49931
|
* a music sheet in any UI using the given {@link IUiFacade}
|
|
@@ -49566,12 +49936,14 @@
|
|
|
49566
49936
|
_startTime = 0;
|
|
49567
49937
|
_trackIndexes = null;
|
|
49568
49938
|
_trackIndexLookup = null;
|
|
49939
|
+
_beatVisibilityChecker = new BoundsLookupVisibilityChecker();
|
|
49569
49940
|
_isDestroyed = false;
|
|
49570
49941
|
_score = null;
|
|
49571
49942
|
_tracks = [];
|
|
49572
49943
|
_actualPlayerMode = exports.PlayerMode.Disabled;
|
|
49573
49944
|
_player;
|
|
49574
49945
|
_renderer;
|
|
49946
|
+
_defaultScrollHandler;
|
|
49575
49947
|
/**
|
|
49576
49948
|
* An indicator by how many midi-ticks the song contents are shifted.
|
|
49577
49949
|
* Grace beats at start might require a shift for the first beat to start at 0.
|
|
@@ -50341,6 +50713,42 @@
|
|
|
50341
50713
|
}
|
|
50342
50714
|
}
|
|
50343
50715
|
_tickCache = null;
|
|
50716
|
+
/**
|
|
50717
|
+
* A custom scroll handler which will be used to handle scrolling operations during playback.
|
|
50718
|
+
*
|
|
50719
|
+
* @category Properties - Player
|
|
50720
|
+
* @since 1.8.0
|
|
50721
|
+
* @example
|
|
50722
|
+
* JavaScript
|
|
50723
|
+
* ```js
|
|
50724
|
+
* const api = new alphaTab.AlphaTabApi(document.querySelector('#alphaTab'));
|
|
50725
|
+
* api.customScrollHandler = {
|
|
50726
|
+
* forceScrollTo(currentBeatBounds) {
|
|
50727
|
+
* const scroll = api.uiFacade.getScrollElement();
|
|
50728
|
+
* api.uiFacade.scrollToY(scroll, currentBeatBounds.barBounds.masterBarBounds.realBounds.y, 0);
|
|
50729
|
+
* },
|
|
50730
|
+
* onBeatCursorUpdating(startBeat, endBeat, cursorMode, relativePosition, actualBeatCursorStartX, actualBeatCursorEndX, actualBeatCursorTransitionDuration) {
|
|
50731
|
+
* const scroll = api.uiFacade.getScrollElement();
|
|
50732
|
+
* api.uiFacade.scrollToY(scroll, startBeat.barBounds.masterBarBounds.realBounds.y, 0);
|
|
50733
|
+
* }
|
|
50734
|
+
* }
|
|
50735
|
+
* ```
|
|
50736
|
+
*
|
|
50737
|
+
* @example
|
|
50738
|
+
* C#
|
|
50739
|
+
* ```cs
|
|
50740
|
+
* var api = new AlphaTabApi<MyControl>(...);
|
|
50741
|
+
* api.CustomScrollHandler = new CustomScrollHandler();
|
|
50742
|
+
* ```
|
|
50743
|
+
*
|
|
50744
|
+
* @example
|
|
50745
|
+
* Android
|
|
50746
|
+
* ```kotlin
|
|
50747
|
+
* val api = AlphaTabApi<MyControl>(...)
|
|
50748
|
+
* api.customScrollHandler = CustomScrollHandler();
|
|
50749
|
+
* ```
|
|
50750
|
+
*/
|
|
50751
|
+
customScrollHandler;
|
|
50344
50752
|
/**
|
|
50345
50753
|
* The tick cache allowing lookup of midi ticks to beats.
|
|
50346
50754
|
* @remarks
|
|
@@ -51319,7 +51727,6 @@
|
|
|
51319
51727
|
_isInitialBeatCursorUpdate = true;
|
|
51320
51728
|
_previousStateForCursor = PlayerState.Paused;
|
|
51321
51729
|
_previousCursorCache = null;
|
|
51322
|
-
_lastScroll = 0;
|
|
51323
51730
|
_destroyCursors() {
|
|
51324
51731
|
if (!this._cursorWrapper) {
|
|
51325
51732
|
return;
|
|
@@ -51330,28 +51737,79 @@
|
|
|
51330
51737
|
this._beatCursor = null;
|
|
51331
51738
|
this._selectionWrapper = null;
|
|
51332
51739
|
}
|
|
51740
|
+
_createCursors() {
|
|
51741
|
+
if (this._cursorWrapper) {
|
|
51742
|
+
return;
|
|
51743
|
+
}
|
|
51744
|
+
const cursors = this.uiFacade.createCursors();
|
|
51745
|
+
if (cursors) {
|
|
51746
|
+
// store options and created elements for fast access
|
|
51747
|
+
this._cursorWrapper = cursors.cursorWrapper;
|
|
51748
|
+
this._barCursor = cursors.barCursor;
|
|
51749
|
+
this._beatCursor = cursors.beatCursor;
|
|
51750
|
+
this._selectionWrapper = cursors.selectionWrapper;
|
|
51751
|
+
this._isInitialBeatCursorUpdate = true;
|
|
51752
|
+
}
|
|
51753
|
+
if (this._currentBeat !== null) {
|
|
51754
|
+
this._cursorUpdateBeat(this._currentBeat, false, this._previousTick > 10, 1, true);
|
|
51755
|
+
}
|
|
51756
|
+
}
|
|
51333
51757
|
_updateCursors() {
|
|
51758
|
+
this._updateScrollHandler();
|
|
51334
51759
|
const enable = this._hasCursor;
|
|
51335
|
-
if (enable
|
|
51336
|
-
|
|
51337
|
-
// Create cursors
|
|
51338
|
-
const cursors = this.uiFacade.createCursors();
|
|
51339
|
-
if (cursors) {
|
|
51340
|
-
// store options and created elements for fast access
|
|
51341
|
-
this._cursorWrapper = cursors.cursorWrapper;
|
|
51342
|
-
this._barCursor = cursors.barCursor;
|
|
51343
|
-
this._beatCursor = cursors.beatCursor;
|
|
51344
|
-
this._selectionWrapper = cursors.selectionWrapper;
|
|
51345
|
-
this._isInitialBeatCursorUpdate = true;
|
|
51346
|
-
}
|
|
51347
|
-
if (this._currentBeat !== null) {
|
|
51348
|
-
this._cursorUpdateBeat(this._currentBeat, false, this._previousTick > 10, 1, true);
|
|
51349
|
-
}
|
|
51760
|
+
if (enable) {
|
|
51761
|
+
this._createCursors();
|
|
51350
51762
|
}
|
|
51351
51763
|
else if (!enable && this._cursorWrapper) {
|
|
51352
51764
|
this._destroyCursors();
|
|
51353
51765
|
}
|
|
51354
51766
|
}
|
|
51767
|
+
_scrollHandlerMode = exports.ScrollMode.Off;
|
|
51768
|
+
_scrollHandlerVertical = true;
|
|
51769
|
+
_updateScrollHandler() {
|
|
51770
|
+
const currentHandler = this._defaultScrollHandler;
|
|
51771
|
+
const scrollMode = this.settings.player.scrollMode;
|
|
51772
|
+
const isVertical = Environment.getLayoutEngineFactory(this.settings.display.layoutMode).vertical;
|
|
51773
|
+
// no change
|
|
51774
|
+
if (this._scrollHandlerMode === scrollMode && this._scrollHandlerVertical === isVertical) {
|
|
51775
|
+
return;
|
|
51776
|
+
}
|
|
51777
|
+
// destroy current handler in favor of new one
|
|
51778
|
+
if (currentHandler) {
|
|
51779
|
+
currentHandler[Symbol.dispose]();
|
|
51780
|
+
const scroll = this.uiFacade.getScrollContainer();
|
|
51781
|
+
this.uiFacade.stopScrolling(scroll);
|
|
51782
|
+
}
|
|
51783
|
+
switch (scrollMode) {
|
|
51784
|
+
case exports.ScrollMode.Off:
|
|
51785
|
+
this._defaultScrollHandler = undefined;
|
|
51786
|
+
break;
|
|
51787
|
+
case exports.ScrollMode.Continuous:
|
|
51788
|
+
if (isVertical) {
|
|
51789
|
+
this._defaultScrollHandler = new VerticalContinuousScrollHandler(this);
|
|
51790
|
+
}
|
|
51791
|
+
else {
|
|
51792
|
+
this._defaultScrollHandler = new HorizontalContinuousScrollHandler(this);
|
|
51793
|
+
}
|
|
51794
|
+
break;
|
|
51795
|
+
case exports.ScrollMode.OffScreen:
|
|
51796
|
+
if (isVertical) {
|
|
51797
|
+
this._defaultScrollHandler = new VerticalOffScreenScrollHandler(this);
|
|
51798
|
+
}
|
|
51799
|
+
else {
|
|
51800
|
+
this._defaultScrollHandler = new HorizontalOffScreenScrollHandler(this);
|
|
51801
|
+
}
|
|
51802
|
+
break;
|
|
51803
|
+
case exports.ScrollMode.Smooth:
|
|
51804
|
+
if (isVertical) {
|
|
51805
|
+
this._defaultScrollHandler = new VerticalSmoothScrollHandler(this);
|
|
51806
|
+
}
|
|
51807
|
+
else {
|
|
51808
|
+
this._defaultScrollHandler = new HorizontalSmoothScrollHandler(this);
|
|
51809
|
+
}
|
|
51810
|
+
break;
|
|
51811
|
+
}
|
|
51812
|
+
}
|
|
51355
51813
|
/**
|
|
51356
51814
|
* updates the cursors to highlight the beat at the specified tick position
|
|
51357
51815
|
* @param tick
|
|
@@ -51362,12 +51820,9 @@
|
|
|
51362
51820
|
this._previousTick = tick;
|
|
51363
51821
|
const cache = this._tickCache;
|
|
51364
51822
|
if (cache) {
|
|
51365
|
-
const
|
|
51366
|
-
if (
|
|
51367
|
-
|
|
51368
|
-
if (beat) {
|
|
51369
|
-
this._cursorUpdateBeat(beat, stop, shouldScroll, cursorSpeed, forceUpdate || this.playerState === PlayerState.Paused);
|
|
51370
|
-
}
|
|
51823
|
+
const beat = cache.findBeatWithChecker(this._beatVisibilityChecker, tick, this._currentBeat);
|
|
51824
|
+
if (beat) {
|
|
51825
|
+
this._cursorUpdateBeat(beat, stop, shouldScroll, cursorSpeed, forceUpdate || this.playerState === PlayerState.Paused);
|
|
51371
51826
|
}
|
|
51372
51827
|
}
|
|
51373
51828
|
}
|
|
@@ -51417,57 +51872,9 @@
|
|
|
51417
51872
|
scrollToCursor() {
|
|
51418
51873
|
const beatBounds = this._currentBeatBounds;
|
|
51419
51874
|
if (beatBounds) {
|
|
51420
|
-
this.
|
|
51421
|
-
|
|
51422
|
-
|
|
51423
|
-
_internalScrollToCursor(barBoundings) {
|
|
51424
|
-
const scrollElement = this.uiFacade.getScrollContainer();
|
|
51425
|
-
const isVertical = Environment.getLayoutEngineFactory(this.settings.display.layoutMode).vertical;
|
|
51426
|
-
const mode = this.settings.player.scrollMode;
|
|
51427
|
-
if (isVertical) {
|
|
51428
|
-
// when scrolling on the y-axis, we preliminary check if the new beat/bar have
|
|
51429
|
-
// moved on the y-axis
|
|
51430
|
-
const y = barBoundings.realBounds.y + this.settings.player.scrollOffsetY;
|
|
51431
|
-
if (y !== this._lastScroll) {
|
|
51432
|
-
this._lastScroll = y;
|
|
51433
|
-
switch (mode) {
|
|
51434
|
-
case exports.ScrollMode.Continuous:
|
|
51435
|
-
const elementOffset = this.uiFacade.getOffset(scrollElement, this.container);
|
|
51436
|
-
this.uiFacade.scrollToY(scrollElement, elementOffset.y + y, this.settings.player.scrollSpeed);
|
|
51437
|
-
break;
|
|
51438
|
-
case exports.ScrollMode.OffScreen:
|
|
51439
|
-
const elementBottom = scrollElement.scrollTop + this.uiFacade.getOffset(null, scrollElement).h;
|
|
51440
|
-
if (barBoundings.visualBounds.y + barBoundings.visualBounds.h >= elementBottom ||
|
|
51441
|
-
barBoundings.visualBounds.y < scrollElement.scrollTop) {
|
|
51442
|
-
const scrollTop = barBoundings.realBounds.y + this.settings.player.scrollOffsetY;
|
|
51443
|
-
this.uiFacade.scrollToY(scrollElement, scrollTop, this.settings.player.scrollSpeed);
|
|
51444
|
-
}
|
|
51445
|
-
break;
|
|
51446
|
-
}
|
|
51447
|
-
}
|
|
51448
|
-
}
|
|
51449
|
-
else {
|
|
51450
|
-
// when scrolling on the x-axis, we preliminary check if the new bar has
|
|
51451
|
-
// moved on the x-axis
|
|
51452
|
-
const x = barBoundings.visualBounds.x;
|
|
51453
|
-
if (x !== this._lastScroll) {
|
|
51454
|
-
this._lastScroll = x;
|
|
51455
|
-
switch (mode) {
|
|
51456
|
-
case exports.ScrollMode.Continuous:
|
|
51457
|
-
const scrollLeftContinuous = barBoundings.realBounds.x + this.settings.player.scrollOffsetX;
|
|
51458
|
-
this._lastScroll = barBoundings.visualBounds.x;
|
|
51459
|
-
this.uiFacade.scrollToX(scrollElement, scrollLeftContinuous, this.settings.player.scrollSpeed);
|
|
51460
|
-
break;
|
|
51461
|
-
case exports.ScrollMode.OffScreen:
|
|
51462
|
-
const elementRight = scrollElement.scrollLeft + this.uiFacade.getOffset(null, scrollElement).w;
|
|
51463
|
-
if (barBoundings.visualBounds.x + barBoundings.visualBounds.w >= elementRight ||
|
|
51464
|
-
barBoundings.visualBounds.x < scrollElement.scrollLeft) {
|
|
51465
|
-
const scrollLeftOffScreen = barBoundings.realBounds.x + this.settings.player.scrollOffsetX;
|
|
51466
|
-
this._lastScroll = barBoundings.visualBounds.x;
|
|
51467
|
-
this.uiFacade.scrollToX(scrollElement, scrollLeftOffScreen, this.settings.player.scrollSpeed);
|
|
51468
|
-
}
|
|
51469
|
-
break;
|
|
51470
|
-
}
|
|
51875
|
+
const handler = this.customScrollHandler ?? this._defaultScrollHandler;
|
|
51876
|
+
if (handler) {
|
|
51877
|
+
handler.forceScrollTo(beatBounds);
|
|
51471
51878
|
}
|
|
51472
51879
|
}
|
|
51473
51880
|
}
|
|
@@ -51483,11 +51890,12 @@
|
|
|
51483
51890
|
}
|
|
51484
51891
|
const isPlayingUpdate = this._player.state === PlayerState.Playing && !stop;
|
|
51485
51892
|
let nextBeatX = barBoundings.visualBounds.x + barBoundings.visualBounds.w;
|
|
51893
|
+
let nextBeatBoundings = null;
|
|
51486
51894
|
// get position of next beat on same system
|
|
51487
51895
|
if (nextBeat && cursorMode === MidiTickLookupFindBeatResultCursorMode.ToNextBext) {
|
|
51488
51896
|
// if we are moving within the same bar or to the next bar
|
|
51489
51897
|
// transition to the next beat, otherwise transition to the end of the bar.
|
|
51490
|
-
|
|
51898
|
+
nextBeatBoundings = cache.findBeat(nextBeat);
|
|
51491
51899
|
if (nextBeatBoundings &&
|
|
51492
51900
|
nextBeatBoundings.barBounds.masterBarBounds.staffSystemBounds === barBoundings.staffSystemBounds) {
|
|
51493
51901
|
nextBeatX = nextBeatBoundings.onNotesX;
|
|
@@ -51513,25 +51921,29 @@
|
|
|
51513
51921
|
beatCursor.transitionToX(0, startBeatX);
|
|
51514
51922
|
beatCursor.setBounds(startBeatX, barBounds.y, 1, barBounds.h);
|
|
51515
51923
|
}
|
|
51924
|
+
// it can happen that the cursor reaches the target position slightly too early (especially on backing tracks)
|
|
51925
|
+
// to avoid the cursor stopping, causing a wierd look, we animate the cursor to the double position in double time.
|
|
51926
|
+
// beatCursor!.transitionToX((duration / cursorSpeed), nextBeatX);
|
|
51927
|
+
const factor = cursorMode === MidiTickLookupFindBeatResultCursorMode.ToNextBext ? 2 : 1;
|
|
51928
|
+
nextBeatX = startBeatX + (nextBeatX - startBeatX) * factor;
|
|
51929
|
+
duration = (duration / cursorSpeed) * factor;
|
|
51516
51930
|
// we need to put the transition to an own animation frame
|
|
51517
51931
|
// otherwise the stop animation above is not applied.
|
|
51518
51932
|
this.uiFacade.beginInvoke(() => {
|
|
51519
|
-
|
|
51520
|
-
// to avoid the cursor stopping, causing a wierd look, we animate the cursor to the double position in double time.
|
|
51521
|
-
// beatCursor!.transitionToX((duration / cursorSpeed), nextBeatX);
|
|
51522
|
-
const factor = cursorMode === MidiTickLookupFindBeatResultCursorMode.ToNextBext ? 2 : 1;
|
|
51523
|
-
const doubleEndBeatX = startBeatX + (nextBeatX - startBeatX) * factor;
|
|
51524
|
-
beatCursor.transitionToX((duration / cursorSpeed) * factor, doubleEndBeatX);
|
|
51933
|
+
beatCursor.transitionToX(duration, nextBeatX);
|
|
51525
51934
|
});
|
|
51526
51935
|
}
|
|
51527
51936
|
else {
|
|
51528
|
-
|
|
51937
|
+
duration = 0;
|
|
51938
|
+
beatCursor.transitionToX(duration, nextBeatX);
|
|
51529
51939
|
beatCursor.setBounds(startBeatX, barBounds.y, 1, barBounds.h);
|
|
51530
51940
|
}
|
|
51531
51941
|
}
|
|
51532
51942
|
else {
|
|
51533
51943
|
// ticking cursor
|
|
51534
|
-
|
|
51944
|
+
duration = 0;
|
|
51945
|
+
nextBeatX = startBeatX;
|
|
51946
|
+
beatCursor.transitionToX(duration, nextBeatX);
|
|
51535
51947
|
beatCursor.setBounds(startBeatX, barBounds.y, 1, barBounds.h);
|
|
51536
51948
|
}
|
|
51537
51949
|
this._isInitialBeatCursorUpdate = false;
|
|
@@ -51554,7 +51966,10 @@
|
|
|
51554
51966
|
shouldNotifyBeatChange = true;
|
|
51555
51967
|
}
|
|
51556
51968
|
if (shouldScroll && !this._isBeatMouseDown && this.settings.player.scrollMode !== exports.ScrollMode.Off) {
|
|
51557
|
-
this.
|
|
51969
|
+
const handler = this.customScrollHandler ?? this._defaultScrollHandler;
|
|
51970
|
+
if (handler) {
|
|
51971
|
+
handler.onBeatCursorUpdating(beatBoundings, nextBeatBoundings === null ? undefined : nextBeatBoundings, cursorMode, startBeatX, nextBeatX, duration);
|
|
51972
|
+
}
|
|
51558
51973
|
}
|
|
51559
51974
|
// trigger an event for others to indicate which beat/bar is played
|
|
51560
51975
|
if (shouldNotifyBeatChange) {
|
|
@@ -52569,6 +52984,7 @@
|
|
|
52569
52984
|
if (this._isDestroyed) {
|
|
52570
52985
|
return;
|
|
52571
52986
|
}
|
|
52987
|
+
this._beatVisibilityChecker.bounds = this.boundsLookup;
|
|
52572
52988
|
this._currentBeat = null;
|
|
52573
52989
|
this._cursorUpdateTick(this._previousTick, false, 1, true, true);
|
|
52574
52990
|
this.postRenderFinished.trigger();
|
|
@@ -52927,6 +53343,7 @@
|
|
|
52927
53343
|
const tickCache = this._tickCache;
|
|
52928
53344
|
if (currentBeat && tickCache) {
|
|
52929
53345
|
this._player.tickPosition = tickCache.getBeatStart(currentBeat.beat);
|
|
53346
|
+
this.scrollToCursor();
|
|
52930
53347
|
}
|
|
52931
53348
|
}
|
|
52932
53349
|
this.uiFacade.triggerEvent(this.container, 'playerStateChanged', e);
|
|
@@ -54887,6 +55304,22 @@
|
|
|
54887
55304
|
canvasElement.style.position = 'relative';
|
|
54888
55305
|
return new HtmlElementContainer(canvasElement);
|
|
54889
55306
|
}
|
|
55307
|
+
setCanvasOverflow(canvasElement, overflow, isVertical) {
|
|
55308
|
+
const html = canvasElement.element;
|
|
55309
|
+
if (overflow === 0) {
|
|
55310
|
+
html.style.boxSizing = '';
|
|
55311
|
+
html.style.paddingRight = '';
|
|
55312
|
+
html.style.paddingBottom = '';
|
|
55313
|
+
}
|
|
55314
|
+
else if (isVertical) {
|
|
55315
|
+
html.style.boxSizing = 'content-box';
|
|
55316
|
+
html.style.paddingBottom = `${overflow}px`;
|
|
55317
|
+
}
|
|
55318
|
+
else {
|
|
55319
|
+
html.style.boxSizing = 'content-box';
|
|
55320
|
+
html.style.paddingRight = `${overflow}px`;
|
|
55321
|
+
}
|
|
55322
|
+
}
|
|
54890
55323
|
triggerEvent(container, name, details = null, originalEvent) {
|
|
54891
55324
|
const element = container.element;
|
|
54892
55325
|
name = `alphaTab.${name}`;
|
|
@@ -55444,54 +55877,79 @@
|
|
|
55444
55877
|
scrollToX(element, scrollTargetY, speed) {
|
|
55445
55878
|
this._internalScrollToX(element.element, scrollTargetY, speed);
|
|
55446
55879
|
}
|
|
55880
|
+
stopScrolling(scrollElement) {
|
|
55881
|
+
// stop any current animation
|
|
55882
|
+
const currentAnimation = this._scrollAnimationLookup.get(scrollElement.element);
|
|
55883
|
+
if (currentAnimation !== undefined) {
|
|
55884
|
+
this._activeScrollAnimations.delete(currentAnimation);
|
|
55885
|
+
}
|
|
55886
|
+
}
|
|
55887
|
+
get _nativeBrowserSmoothScroll() {
|
|
55888
|
+
const settings = this._api.settings.player;
|
|
55889
|
+
return settings.nativeBrowserSmoothScroll && settings.scrollMode !== exports.ScrollMode.Smooth;
|
|
55890
|
+
}
|
|
55891
|
+
_scrollAnimationId = 0;
|
|
55892
|
+
_activeScrollAnimations = new Set();
|
|
55893
|
+
_scrollAnimationLookup = new Map();
|
|
55447
55894
|
_internalScrollToY(element, scrollTargetY, speed) {
|
|
55448
|
-
if (this.
|
|
55895
|
+
if (this._nativeBrowserSmoothScroll) {
|
|
55449
55896
|
element.scrollTo({
|
|
55450
55897
|
top: scrollTargetY,
|
|
55451
55898
|
behavior: 'smooth'
|
|
55452
55899
|
});
|
|
55453
55900
|
}
|
|
55454
55901
|
else {
|
|
55455
|
-
|
|
55456
|
-
|
|
55457
|
-
|
|
55458
|
-
const step = (x) => {
|
|
55459
|
-
if (start === 0) {
|
|
55460
|
-
start = x;
|
|
55461
|
-
}
|
|
55462
|
-
const time = x - start;
|
|
55463
|
-
const percent = Math.min(time / speed, 1);
|
|
55464
|
-
element.scrollTop = (startY + diff * percent) | 0;
|
|
55465
|
-
if (time < speed) {
|
|
55466
|
-
window.requestAnimationFrame(step);
|
|
55467
|
-
}
|
|
55468
|
-
};
|
|
55469
|
-
window.requestAnimationFrame(step);
|
|
55902
|
+
this._internalScrollTo(element, element.scrollTop, scrollTargetY, speed, scroll => {
|
|
55903
|
+
element.scrollTop = scroll;
|
|
55904
|
+
});
|
|
55470
55905
|
}
|
|
55471
55906
|
}
|
|
55907
|
+
_internalScrollTo(element, startScroll, endScroll, scrollDuration, setValue) {
|
|
55908
|
+
// stop any current animation
|
|
55909
|
+
const currentAnimation = this._scrollAnimationLookup.get(element);
|
|
55910
|
+
if (currentAnimation !== undefined) {
|
|
55911
|
+
this._activeScrollAnimations.delete(currentAnimation);
|
|
55912
|
+
}
|
|
55913
|
+
if (scrollDuration === 0) {
|
|
55914
|
+
setValue(endScroll);
|
|
55915
|
+
return;
|
|
55916
|
+
}
|
|
55917
|
+
// start new animation
|
|
55918
|
+
const animationId = this._scrollAnimationId++;
|
|
55919
|
+
this._scrollAnimationLookup.set(element, animationId);
|
|
55920
|
+
this._activeScrollAnimations.add(animationId);
|
|
55921
|
+
const diff = endScroll - startScroll;
|
|
55922
|
+
let start = 0;
|
|
55923
|
+
const step = (x) => {
|
|
55924
|
+
if (!this._activeScrollAnimations.has(animationId)) {
|
|
55925
|
+
return;
|
|
55926
|
+
}
|
|
55927
|
+
if (start === 0) {
|
|
55928
|
+
start = x;
|
|
55929
|
+
}
|
|
55930
|
+
const time = x - start;
|
|
55931
|
+
const percent = Math.min(time / scrollDuration, 1);
|
|
55932
|
+
setValue((startScroll + diff * percent) | 0);
|
|
55933
|
+
if (time < scrollDuration) {
|
|
55934
|
+
window.requestAnimationFrame(step);
|
|
55935
|
+
}
|
|
55936
|
+
else {
|
|
55937
|
+
this._activeScrollAnimations.delete(animationId);
|
|
55938
|
+
}
|
|
55939
|
+
};
|
|
55940
|
+
window.requestAnimationFrame(step);
|
|
55941
|
+
}
|
|
55472
55942
|
_internalScrollToX(element, scrollTargetX, speed) {
|
|
55473
|
-
if (this.
|
|
55943
|
+
if (this._nativeBrowserSmoothScroll) {
|
|
55474
55944
|
element.scrollTo({
|
|
55475
55945
|
left: scrollTargetX,
|
|
55476
55946
|
behavior: 'smooth'
|
|
55477
55947
|
});
|
|
55478
55948
|
}
|
|
55479
55949
|
else {
|
|
55480
|
-
|
|
55481
|
-
|
|
55482
|
-
|
|
55483
|
-
const step = (t) => {
|
|
55484
|
-
if (start === 0) {
|
|
55485
|
-
start = t;
|
|
55486
|
-
}
|
|
55487
|
-
const time = t - start;
|
|
55488
|
-
const percent = Math.min(time / speed, 1);
|
|
55489
|
-
element.scrollLeft = (startX + diff * percent) | 0;
|
|
55490
|
-
if (time < speed) {
|
|
55491
|
-
window.requestAnimationFrame(step);
|
|
55492
|
-
}
|
|
55493
|
-
};
|
|
55494
|
-
window.requestAnimationFrame(step);
|
|
55950
|
+
this._internalScrollTo(element, element.scrollLeft, scrollTargetX, speed, scroll => {
|
|
55951
|
+
element.scrollLeft = scroll;
|
|
55952
|
+
});
|
|
55495
55953
|
}
|
|
55496
55954
|
}
|
|
55497
55955
|
createBackingTrackPlayer() {
|
|
@@ -60576,8 +61034,10 @@
|
|
|
60576
61034
|
height = 0;
|
|
60577
61035
|
index = 0;
|
|
60578
61036
|
staffIndex = 0;
|
|
61037
|
+
isVisible = false;
|
|
61038
|
+
_emptyBarCount = 0;
|
|
60579
61039
|
get isFirstInSystem() {
|
|
60580
|
-
return this.
|
|
61040
|
+
return this.system.firstVisibleStaff === this;
|
|
60581
61041
|
}
|
|
60582
61042
|
topEffectInfos = [];
|
|
60583
61043
|
bottomEffectInfos = [];
|
|
@@ -60612,10 +61072,11 @@
|
|
|
60612
61072
|
get contentBottom() {
|
|
60613
61073
|
return this.y + this.topPadding + this.topOverflow + this.staffBottom;
|
|
60614
61074
|
}
|
|
60615
|
-
constructor(trackIndex, staff, factory) {
|
|
61075
|
+
constructor(system, trackIndex, staff, factory) {
|
|
60616
61076
|
this._factory = factory;
|
|
60617
61077
|
this.trackIndex = trackIndex;
|
|
60618
61078
|
this.modelStaff = staff;
|
|
61079
|
+
this.system = system;
|
|
60619
61080
|
for (const b of factory.effectBands) {
|
|
60620
61081
|
if (b.shouldCreate && !b.shouldCreate(staff)) {
|
|
60621
61082
|
continue;
|
|
@@ -60631,6 +61092,7 @@
|
|
|
60631
61092
|
break;
|
|
60632
61093
|
}
|
|
60633
61094
|
}
|
|
61095
|
+
this._updateVisibility();
|
|
60634
61096
|
}
|
|
60635
61097
|
getSharedLayoutData(key, def) {
|
|
60636
61098
|
if (this._sharedLayoutData.has(key)) {
|
|
@@ -60657,6 +61119,20 @@
|
|
|
60657
61119
|
renderer.reLayout();
|
|
60658
61120
|
this.barRenderers.push(renderer);
|
|
60659
61121
|
this.system.layout.registerBarRenderer(this.staffId, renderer);
|
|
61122
|
+
if (renderer.bar.isEmpty || renderer.bar.isRestOnly) {
|
|
61123
|
+
this._emptyBarCount++;
|
|
61124
|
+
}
|
|
61125
|
+
this._updateVisibility();
|
|
61126
|
+
}
|
|
61127
|
+
_updateVisibility() {
|
|
61128
|
+
const stylesheet = this.modelStaff.track.score.stylesheet;
|
|
61129
|
+
const canHideEmptyStaves = stylesheet.hideEmptyStaves && (stylesheet.hideEmptyStavesInFirstSystem || this.system.index > 0);
|
|
61130
|
+
if (canHideEmptyStaves) {
|
|
61131
|
+
this.isVisible = this._emptyBarCount < this.barRenderers.length;
|
|
61132
|
+
}
|
|
61133
|
+
else {
|
|
61134
|
+
this.isVisible = true;
|
|
61135
|
+
}
|
|
60660
61136
|
}
|
|
60661
61137
|
addBar(bar, layoutingInfo, additionalMultiBarsRestBars) {
|
|
60662
61138
|
const renderer = this._factory.create(this.system.layout.renderer, bar);
|
|
@@ -60676,6 +61152,10 @@
|
|
|
60676
61152
|
}
|
|
60677
61153
|
this.barRenderers.push(renderer);
|
|
60678
61154
|
this.system.layout.registerBarRenderer(this.staffId, renderer);
|
|
61155
|
+
if (bar.isEmpty || bar.isRestOnly) {
|
|
61156
|
+
this._emptyBarCount++;
|
|
61157
|
+
}
|
|
61158
|
+
this._updateVisibility();
|
|
60679
61159
|
}
|
|
60680
61160
|
revertLastBar() {
|
|
60681
61161
|
this._sharedLayoutData = new Map();
|
|
@@ -60686,6 +61166,10 @@
|
|
|
60686
61166
|
for (const r of this.barRenderers) {
|
|
60687
61167
|
r.afterStaffBarReverted();
|
|
60688
61168
|
}
|
|
61169
|
+
if (lastBar.bar.isEmpty || lastBar.bar.isRestOnly) {
|
|
61170
|
+
this._emptyBarCount--;
|
|
61171
|
+
}
|
|
61172
|
+
this._updateVisibility();
|
|
60689
61173
|
return lastBar;
|
|
60690
61174
|
}
|
|
60691
61175
|
scaleToWidth(width) {
|
|
@@ -60796,6 +61280,7 @@
|
|
|
60796
61280
|
this.height += this.topPadding + topOverflow + this.bottomOverflow + this.bottomPadding;
|
|
60797
61281
|
}
|
|
60798
61282
|
this.height = Math.ceil(this.height);
|
|
61283
|
+
this._updateVisibility();
|
|
60799
61284
|
}
|
|
60800
61285
|
paint(cx, cy, canvas, startIndex, count) {
|
|
60801
61286
|
if (this.height === 0 || count === 0) {
|
|
@@ -61196,6 +61681,8 @@
|
|
|
61196
61681
|
track;
|
|
61197
61682
|
staffSystem;
|
|
61198
61683
|
staves = [];
|
|
61684
|
+
firstVisibleStaff;
|
|
61685
|
+
lastVisibleStaff;
|
|
61199
61686
|
bracket = null;
|
|
61200
61687
|
constructor(staffSystem, track) {
|
|
61201
61688
|
this.staffSystem = staffSystem;
|
|
@@ -61210,18 +61697,47 @@
|
|
|
61210
61697
|
* @internal
|
|
61211
61698
|
*/
|
|
61212
61699
|
class SystemBracket {
|
|
61213
|
-
|
|
61214
|
-
|
|
61700
|
+
_system;
|
|
61701
|
+
firstStaffInBracket;
|
|
61702
|
+
lastStaffInBracket;
|
|
61703
|
+
firstVisibleStaffInBracket;
|
|
61704
|
+
lastVisibleStaffInBracket;
|
|
61215
61705
|
drawAsBrace = false;
|
|
61216
61706
|
braceScale = 1;
|
|
61217
61707
|
width = 0;
|
|
61218
61708
|
index = 0;
|
|
61219
|
-
|
|
61220
|
-
|
|
61709
|
+
canPaint = false;
|
|
61710
|
+
constructor(system) {
|
|
61711
|
+
this._system = system;
|
|
61712
|
+
}
|
|
61713
|
+
updateCanPaint() {
|
|
61714
|
+
let firstVisibleStaff = undefined;
|
|
61715
|
+
let lastVisibleStaff = undefined;
|
|
61716
|
+
for (let i = this.firstStaffInBracket.index; i <= this.lastStaffInBracket.index; i++) {
|
|
61717
|
+
const staff = this._system.allStaves[i];
|
|
61718
|
+
if (staff.isVisible) {
|
|
61719
|
+
if (!firstVisibleStaff) {
|
|
61720
|
+
firstVisibleStaff = staff;
|
|
61721
|
+
}
|
|
61722
|
+
lastVisibleStaff = staff;
|
|
61723
|
+
}
|
|
61724
|
+
}
|
|
61725
|
+
this.firstVisibleStaffInBracket = firstVisibleStaff;
|
|
61726
|
+
this.lastVisibleStaffInBracket = lastVisibleStaff;
|
|
61727
|
+
if (!firstVisibleStaff || !lastVisibleStaff) {
|
|
61728
|
+
this.canPaint = false;
|
|
61729
|
+
return;
|
|
61730
|
+
}
|
|
61731
|
+
// single staff brackets?
|
|
61732
|
+
const singleStaffBrackets = this._system.layout.renderer.score.stylesheet.showSingleStaffBrackets;
|
|
61733
|
+
if (!singleStaffBrackets && firstVisibleStaff === lastVisibleStaff) {
|
|
61734
|
+
this.canPaint = false;
|
|
61735
|
+
return;
|
|
61736
|
+
}
|
|
61737
|
+
this.canPaint = true;
|
|
61221
61738
|
}
|
|
61222
61739
|
finalizeBracket(smuflMetrics) {
|
|
61223
|
-
|
|
61224
|
-
if (this.firstStaffInBracket === this.lastStaffInBracket) {
|
|
61740
|
+
if (!this.canPaint) {
|
|
61225
61741
|
this.width = 0;
|
|
61226
61742
|
return;
|
|
61227
61743
|
}
|
|
@@ -61235,11 +61751,11 @@
|
|
|
61235
61751
|
else {
|
|
61236
61752
|
this.width = smuflMetrics.bracketThickness;
|
|
61237
61753
|
}
|
|
61238
|
-
if (!this.drawAsBrace
|
|
61754
|
+
if (!this.drawAsBrace) {
|
|
61239
61755
|
return;
|
|
61240
61756
|
}
|
|
61241
|
-
const firstStart = this.
|
|
61242
|
-
const lastEnd = this.
|
|
61757
|
+
const firstStart = this.firstVisibleStaffInBracket.contentTop;
|
|
61758
|
+
const lastEnd = this.lastVisibleStaffInBracket.contentBottom;
|
|
61243
61759
|
const requiredHeight = lastEnd - firstStart;
|
|
61244
61760
|
const requiredScaleForBracket = requiredHeight / bravuraBraceHeightAtMusicFontSize;
|
|
61245
61761
|
this.braceScale = requiredScaleForBracket;
|
|
@@ -61251,8 +61767,8 @@
|
|
|
61251
61767
|
*/
|
|
61252
61768
|
class SingleTrackSystemBracket extends SystemBracket {
|
|
61253
61769
|
track;
|
|
61254
|
-
constructor(track) {
|
|
61255
|
-
super();
|
|
61770
|
+
constructor(system, track) {
|
|
61771
|
+
super(system);
|
|
61256
61772
|
this.track = track;
|
|
61257
61773
|
this.drawAsBrace = SingleTrackSystemBracket.isTrackDrawAsBrace(track);
|
|
61258
61774
|
}
|
|
@@ -61317,6 +61833,7 @@
|
|
|
61317
61833
|
topPadding;
|
|
61318
61834
|
bottomPadding;
|
|
61319
61835
|
allStaves = [];
|
|
61836
|
+
firstVisibleStaff;
|
|
61320
61837
|
constructor(layout) {
|
|
61321
61838
|
this.layout = layout;
|
|
61322
61839
|
this.topPadding = layout.renderer.settings.display.systemPaddingTop;
|
|
@@ -61335,14 +61852,40 @@
|
|
|
61335
61852
|
this.masterBarsRenderers.push(renderers);
|
|
61336
61853
|
renderers.layoutingInfo.preBeatSize = 0;
|
|
61337
61854
|
let src = 0;
|
|
61338
|
-
|
|
61339
|
-
|
|
61340
|
-
|
|
61341
|
-
|
|
61855
|
+
let firstVisibleStaff = undefined;
|
|
61856
|
+
let anyStaffVisible = false;
|
|
61857
|
+
for (const g of this.staves) {
|
|
61858
|
+
let firstVisibleStaffInGroup = undefined;
|
|
61859
|
+
let lastVisibleStaffInGroup = undefined;
|
|
61860
|
+
for (const s of g.staves) {
|
|
61342
61861
|
const renderer = renderers.renderers[src++];
|
|
61343
61862
|
s.addBarRenderer(renderer);
|
|
61863
|
+
if (s.isVisible) {
|
|
61864
|
+
anyStaffVisible = true;
|
|
61865
|
+
if (!firstVisibleStaffInGroup) {
|
|
61866
|
+
firstVisibleStaffInGroup = s;
|
|
61867
|
+
}
|
|
61868
|
+
if (!firstVisibleStaff) {
|
|
61869
|
+
firstVisibleStaff = s;
|
|
61870
|
+
}
|
|
61871
|
+
lastVisibleStaffInGroup = s;
|
|
61872
|
+
}
|
|
61873
|
+
}
|
|
61874
|
+
g.firstVisibleStaff = firstVisibleStaffInGroup;
|
|
61875
|
+
g.lastVisibleStaff = lastVisibleStaffInGroup;
|
|
61876
|
+
if (!firstVisibleStaff) {
|
|
61877
|
+
firstVisibleStaff = firstVisibleStaffInGroup;
|
|
61344
61878
|
}
|
|
61345
61879
|
}
|
|
61880
|
+
if (!anyStaffVisible) {
|
|
61881
|
+
const group = this.staves[0];
|
|
61882
|
+
const firstStaff = group.staves[0];
|
|
61883
|
+
firstStaff.isVisible = true;
|
|
61884
|
+
group.firstVisibleStaff = firstStaff;
|
|
61885
|
+
group.lastVisibleStaff = firstStaff;
|
|
61886
|
+
firstVisibleStaff = firstStaff;
|
|
61887
|
+
}
|
|
61888
|
+
this.firstVisibleStaff = firstVisibleStaff;
|
|
61346
61889
|
this._calculateAccoladeSpacing(tracks);
|
|
61347
61890
|
this._updateWidthFromLastBar();
|
|
61348
61891
|
return renderers;
|
|
@@ -61353,15 +61896,26 @@
|
|
|
61353
61896
|
result.layoutingInfo = new BarLayoutingInfo();
|
|
61354
61897
|
result.masterBar = tracks[0].score.masterBars[barIndex];
|
|
61355
61898
|
this.masterBarsRenderers.push(result);
|
|
61899
|
+
let firstVisibleStaff = undefined;
|
|
61900
|
+
let anyStaffVisible = false;
|
|
61356
61901
|
// add renderers
|
|
61357
61902
|
const barLayoutingInfo = result.layoutingInfo;
|
|
61358
61903
|
for (const g of this.staves) {
|
|
61904
|
+
let firstVisibleStaffInGroup = undefined;
|
|
61905
|
+
let lastVisibleStaffInGroup = undefined;
|
|
61359
61906
|
for (const s of g.staves) {
|
|
61360
61907
|
const bar = g.track.staves[s.modelStaff.index].bars[barIndex];
|
|
61361
61908
|
const additionalMultiBarsRestBars = additionalMultiBarRestIndexes == null
|
|
61362
61909
|
? null
|
|
61363
61910
|
: additionalMultiBarRestIndexes.map(b => g.track.staves[s.modelStaff.index].bars[b]);
|
|
61364
61911
|
s.addBar(bar, barLayoutingInfo, additionalMultiBarsRestBars);
|
|
61912
|
+
if (s.isVisible) {
|
|
61913
|
+
anyStaffVisible = true;
|
|
61914
|
+
if (!firstVisibleStaffInGroup) {
|
|
61915
|
+
firstVisibleStaffInGroup = s;
|
|
61916
|
+
}
|
|
61917
|
+
lastVisibleStaffInGroup = s;
|
|
61918
|
+
}
|
|
61365
61919
|
const renderer = s.barRenderers[s.barRenderers.length - 1];
|
|
61366
61920
|
result.renderers.push(renderer);
|
|
61367
61921
|
if (renderer.isLinkedToPrevious) {
|
|
@@ -61371,7 +61925,21 @@
|
|
|
61371
61925
|
result.canWrap = false;
|
|
61372
61926
|
}
|
|
61373
61927
|
}
|
|
61928
|
+
g.firstVisibleStaff = firstVisibleStaffInGroup;
|
|
61929
|
+
g.lastVisibleStaff = lastVisibleStaffInGroup;
|
|
61930
|
+
if (!firstVisibleStaff) {
|
|
61931
|
+
firstVisibleStaff = firstVisibleStaffInGroup;
|
|
61932
|
+
}
|
|
61933
|
+
}
|
|
61934
|
+
if (!anyStaffVisible) {
|
|
61935
|
+
const group = this.staves[0];
|
|
61936
|
+
const firstStaff = group.staves[0];
|
|
61937
|
+
firstStaff.isVisible = true;
|
|
61938
|
+
group.firstVisibleStaff = firstStaff;
|
|
61939
|
+
group.lastVisibleStaff = firstStaff;
|
|
61940
|
+
firstVisibleStaff = firstStaff;
|
|
61374
61941
|
}
|
|
61942
|
+
this.firstVisibleStaff = firstVisibleStaff;
|
|
61375
61943
|
this._calculateAccoladeSpacing(tracks);
|
|
61376
61944
|
barLayoutingInfo.finish();
|
|
61377
61945
|
// ensure same widths of new renderer
|
|
@@ -61384,19 +61952,35 @@
|
|
|
61384
61952
|
this.masterBarsRenderers.splice(this.masterBarsRenderers.length - 1, 1);
|
|
61385
61953
|
let width = 0;
|
|
61386
61954
|
let barDisplayScale = 0;
|
|
61387
|
-
|
|
61388
|
-
|
|
61389
|
-
|
|
61390
|
-
|
|
61391
|
-
|
|
61392
|
-
|
|
61955
|
+
let firstVisibleStaff = undefined;
|
|
61956
|
+
for (const g of this.staves) {
|
|
61957
|
+
let firstVisibleStaffInGroup = undefined;
|
|
61958
|
+
let lastVisibleStaffInGroup = undefined;
|
|
61959
|
+
for (const s of g.staves) {
|
|
61960
|
+
const lastBar = s.revertLastBar();
|
|
61961
|
+
const computedWidth = lastBar.computedWidth;
|
|
61962
|
+
if (computedWidth > width) {
|
|
61963
|
+
width = computedWidth;
|
|
61964
|
+
}
|
|
61965
|
+
const newBarDisplayScale = lastBar.barDisplayScale;
|
|
61966
|
+
if (newBarDisplayScale > barDisplayScale) {
|
|
61967
|
+
barDisplayScale = newBarDisplayScale;
|
|
61968
|
+
}
|
|
61969
|
+
lastBar.afterReverted();
|
|
61970
|
+
if (s.isVisible) {
|
|
61971
|
+
if (!firstVisibleStaffInGroup) {
|
|
61972
|
+
firstVisibleStaffInGroup = s;
|
|
61973
|
+
}
|
|
61974
|
+
lastVisibleStaffInGroup = s;
|
|
61975
|
+
}
|
|
61393
61976
|
}
|
|
61394
|
-
|
|
61395
|
-
|
|
61396
|
-
|
|
61977
|
+
g.firstVisibleStaff = firstVisibleStaffInGroup;
|
|
61978
|
+
g.lastVisibleStaff = lastVisibleStaffInGroup;
|
|
61979
|
+
if (!firstVisibleStaff) {
|
|
61980
|
+
firstVisibleStaff = firstVisibleStaffInGroup;
|
|
61397
61981
|
}
|
|
61398
|
-
lastBar.afterReverted();
|
|
61399
61982
|
}
|
|
61983
|
+
this.firstVisibleStaff = firstVisibleStaff;
|
|
61400
61984
|
this.width -= width;
|
|
61401
61985
|
this.computedWidth -= width;
|
|
61402
61986
|
this.totalBarDisplayScale -= barDisplayScale;
|
|
@@ -61478,8 +62062,8 @@
|
|
|
61478
62062
|
}
|
|
61479
62063
|
}
|
|
61480
62064
|
}
|
|
62065
|
+
this.accoladeWidth += settings.display.systemLabelPaddingLeft;
|
|
61481
62066
|
if (hasAnyTrackName) {
|
|
61482
|
-
this.accoladeWidth += settings.display.systemLabelPaddingLeft;
|
|
61483
62067
|
this.accoladeWidth += settings.display.systemLabelPaddingRight;
|
|
61484
62068
|
}
|
|
61485
62069
|
}
|
|
@@ -61503,6 +62087,7 @@
|
|
|
61503
62087
|
}
|
|
61504
62088
|
let braceWidth = 0;
|
|
61505
62089
|
for (const b of this._brackets) {
|
|
62090
|
+
b.updateCanPaint();
|
|
61506
62091
|
b.finalizeBracket(settings.display.resources.engravingSettings);
|
|
61507
62092
|
braceWidth = Math.max(braceWidth, b.width);
|
|
61508
62093
|
}
|
|
@@ -61510,6 +62095,12 @@
|
|
|
61510
62095
|
this.width += this.accoladeWidth;
|
|
61511
62096
|
this.computedWidth += this.accoladeWidth;
|
|
61512
62097
|
}
|
|
62098
|
+
else {
|
|
62099
|
+
for (const b of this._brackets) {
|
|
62100
|
+
b.updateCanPaint();
|
|
62101
|
+
b.finalizeBracket(settings.display.resources.engravingSettings);
|
|
62102
|
+
}
|
|
62103
|
+
}
|
|
61513
62104
|
}
|
|
61514
62105
|
_getStaffTrackGroup(track) {
|
|
61515
62106
|
for (let i = 0, j = this.staves.length; i < j; i++) {
|
|
@@ -61539,12 +62130,12 @@
|
|
|
61539
62130
|
break;
|
|
61540
62131
|
case BracketExtendMode.GroupStaves:
|
|
61541
62132
|
// when grouping staves, we create one bracket for the whole track across all staves
|
|
61542
|
-
bracket = new SingleTrackSystemBracket(track);
|
|
62133
|
+
bracket = new SingleTrackSystemBracket(this, track);
|
|
61543
62134
|
bracket.index = this._brackets.length;
|
|
61544
62135
|
this._brackets.push(bracket);
|
|
61545
62136
|
break;
|
|
61546
62137
|
case BracketExtendMode.GroupSimilarInstruments:
|
|
61547
|
-
bracket = new SimilarInstrumentSystemBracket(track);
|
|
62138
|
+
bracket = new SimilarInstrumentSystemBracket(this, track);
|
|
61548
62139
|
bracket.index = this._brackets.length;
|
|
61549
62140
|
this._brackets.push(bracket);
|
|
61550
62141
|
break;
|
|
@@ -61591,8 +62182,10 @@
|
|
|
61591
62182
|
}
|
|
61592
62183
|
}
|
|
61593
62184
|
paintPartial(cx, cy, canvas, startIndex, count) {
|
|
61594
|
-
for (
|
|
61595
|
-
|
|
62185
|
+
for (const s of this.allStaves) {
|
|
62186
|
+
if (s.isVisible) {
|
|
62187
|
+
s.paint(cx, cy, canvas, startIndex, count);
|
|
62188
|
+
}
|
|
61596
62189
|
}
|
|
61597
62190
|
const res = this.layout.renderer.settings.display.resources;
|
|
61598
62191
|
if (this.staves.length > 0 && startIndex === 0) {
|
|
@@ -61629,9 +62222,9 @@
|
|
|
61629
62222
|
const oldBaseLine = canvas.textBaseline;
|
|
61630
62223
|
const oldTextAlign = canvas.textAlign;
|
|
61631
62224
|
for (const g of this.staves) {
|
|
61632
|
-
if (g.
|
|
61633
|
-
const firstStart = cy + g.
|
|
61634
|
-
const lastEnd = cy + g.
|
|
62225
|
+
if (g.firstVisibleStaff) {
|
|
62226
|
+
const firstStart = cy + g.firstVisibleStaff.contentTop;
|
|
62227
|
+
const lastEnd = cy + g.lastVisibleStaff.contentBottom;
|
|
61635
62228
|
let trackNameText = '';
|
|
61636
62229
|
switch (trackNameMode) {
|
|
61637
62230
|
case TrackNameMode.FullName:
|
|
@@ -61685,6 +62278,9 @@
|
|
|
61685
62278
|
if (this.allStaves.length > 0 && needsSystemBarLine) {
|
|
61686
62279
|
let previousStaffInBracket = null;
|
|
61687
62280
|
for (const s of this.allStaves) {
|
|
62281
|
+
if (!s.isVisible) {
|
|
62282
|
+
continue;
|
|
62283
|
+
}
|
|
61688
62284
|
if (previousStaffInBracket !== null) {
|
|
61689
62285
|
const previousBottom = previousStaffInBracket.contentBottom;
|
|
61690
62286
|
const thisTop = s.contentTop;
|
|
@@ -61711,17 +62307,17 @@
|
|
|
61711
62307
|
const settings = this.layout.renderer.settings;
|
|
61712
62308
|
for (const bracket of this._brackets) {
|
|
61713
62309
|
if (bracket.canPaint) {
|
|
61714
|
-
const barStartX = cx + bracket.
|
|
62310
|
+
const barStartX = cx + bracket.firstVisibleStaffInBracket.x;
|
|
61715
62311
|
const barSize = bracket.width;
|
|
61716
62312
|
const barOffset = settings.display.accoladeBarPaddingRight;
|
|
61717
|
-
const firstStart = cy + bracket.
|
|
61718
|
-
const lastEnd = cy + bracket.
|
|
62313
|
+
const firstStart = cy + bracket.firstVisibleStaffInBracket.contentTop;
|
|
62314
|
+
const lastEnd = cy + bracket.lastVisibleStaffInBracket.contentBottom;
|
|
61719
62315
|
let accoladeStart = firstStart;
|
|
61720
62316
|
let accoladeEnd = lastEnd;
|
|
61721
62317
|
if (bracket.drawAsBrace) {
|
|
61722
62318
|
CanvasHelper.fillMusicFontSymbolSafe(canvas, barStartX - barOffset - barSize, accoladeEnd, bracket.braceScale, MusicFontSymbol.Brace);
|
|
61723
62319
|
}
|
|
61724
|
-
else if (bracket.
|
|
62320
|
+
else if (bracket.firstVisibleStaffInBracket !== bracket.lastVisibleStaffInBracket) {
|
|
61725
62321
|
// brackets typically overflow by 1/4 staff-space
|
|
61726
62322
|
const smuflMetrics = settings.display.resources.engravingSettings;
|
|
61727
62323
|
const bracketOverflow = smuflMetrics.oneStaffSpace * 0.25;
|
|
@@ -61753,40 +62349,86 @@
|
|
|
61753
62349
|
this.bottomPadding = Math.max(this.bottomPadding, neededHeight);
|
|
61754
62350
|
this._hasSystemSeparator = true;
|
|
61755
62351
|
}
|
|
62352
|
+
const anyStaffVisible = this._finalizeTrackGroups();
|
|
62353
|
+
// for now we always force one staff to be visible.
|
|
62354
|
+
// making also whole systems invisible needs separate attention (also on player cursor handling)
|
|
62355
|
+
if (!anyStaffVisible) {
|
|
62356
|
+
const group = this.staves[0];
|
|
62357
|
+
const firstStaff = group.staves[0];
|
|
62358
|
+
firstStaff.isVisible = true;
|
|
62359
|
+
this._finalizeTrackGroups(true);
|
|
62360
|
+
}
|
|
62361
|
+
for (const b of this._brackets) {
|
|
62362
|
+
b.finalizeBracket(settings.display.resources.engravingSettings);
|
|
62363
|
+
}
|
|
62364
|
+
}
|
|
62365
|
+
_finalizeTrackGroups(onlyFirstGroup = false) {
|
|
61756
62366
|
let currentY = 0;
|
|
62367
|
+
const settings = this.layout.renderer.settings;
|
|
61757
62368
|
const smufl = settings.display.resources.engravingSettings;
|
|
61758
62369
|
const topBracketSpikeHeight = smufl.glyphHeights.get(MusicFontSymbol.BracketTop);
|
|
61759
62370
|
const bottomBracketSpikeHeight = smufl.glyphHeights.get(MusicFontSymbol.BracketBottom);
|
|
61760
62371
|
let previousStaff = undefined;
|
|
61761
|
-
|
|
61762
|
-
|
|
61763
|
-
|
|
61764
|
-
|
|
61765
|
-
|
|
61766
|
-
const
|
|
61767
|
-
|
|
61768
|
-
|
|
61769
|
-
|
|
61770
|
-
|
|
61771
|
-
|
|
62372
|
+
let endSpikeOverflow = 0;
|
|
62373
|
+
let anyStaffVisible = false;
|
|
62374
|
+
for (const group of this.staves) {
|
|
62375
|
+
let firstVisibleStaffInGroup = undefined;
|
|
62376
|
+
let lastVisibleStaffInGroup = undefined;
|
|
62377
|
+
for (const staff of group.staves) {
|
|
62378
|
+
// check if we need "in-between padding"
|
|
62379
|
+
if (previousStaff !== undefined && previousStaff.trackIndex !== staff.trackIndex) {
|
|
62380
|
+
currentY += settings.display.trackStaffPaddingBetween;
|
|
62381
|
+
}
|
|
62382
|
+
const bracket = this._staffToBracket.has(staff) ? this._staffToBracket.get(staff) : undefined;
|
|
62383
|
+
const hasBracket = bracket && !bracket.drawAsBrace && bracket.canPaint;
|
|
62384
|
+
if (hasBracket && bracket.firstStaffInBracket === staff) {
|
|
62385
|
+
const spikeOverflow = topBracketSpikeHeight - staff.topOverflow;
|
|
62386
|
+
if (spikeOverflow > 0) {
|
|
62387
|
+
currentY += spikeOverflow;
|
|
62388
|
+
}
|
|
62389
|
+
}
|
|
62390
|
+
staff.x = this.accoladeWidth;
|
|
62391
|
+
staff.y = currentY;
|
|
62392
|
+
if (!onlyFirstGroup) {
|
|
62393
|
+
staff.finalizeStaff();
|
|
62394
|
+
}
|
|
62395
|
+
if (staff.isVisible) {
|
|
62396
|
+
currentY += staff.height;
|
|
62397
|
+
anyStaffVisible = true;
|
|
62398
|
+
previousStaff = staff;
|
|
62399
|
+
if (!firstVisibleStaffInGroup) {
|
|
62400
|
+
firstVisibleStaffInGroup = staff;
|
|
62401
|
+
}
|
|
62402
|
+
lastVisibleStaffInGroup = staff;
|
|
62403
|
+
}
|
|
62404
|
+
endSpikeOverflow = 0;
|
|
62405
|
+
if (hasBracket && bracket.lastStaffInBracket === staff) {
|
|
62406
|
+
const spikeOverflow = bottomBracketSpikeHeight - staff.bottomOverflow;
|
|
62407
|
+
if (spikeOverflow > 0) {
|
|
62408
|
+
if (staff.isVisible) {
|
|
62409
|
+
currentY += spikeOverflow;
|
|
62410
|
+
}
|
|
62411
|
+
else {
|
|
62412
|
+
endSpikeOverflow = spikeOverflow;
|
|
62413
|
+
}
|
|
62414
|
+
}
|
|
61772
62415
|
}
|
|
61773
62416
|
}
|
|
61774
|
-
|
|
61775
|
-
|
|
61776
|
-
|
|
61777
|
-
|
|
61778
|
-
|
|
61779
|
-
|
|
61780
|
-
|
|
61781
|
-
currentY += spikeOverflow;
|
|
61782
|
-
}
|
|
62417
|
+
group.firstVisibleStaff = firstVisibleStaffInGroup;
|
|
62418
|
+
group.lastVisibleStaff = lastVisibleStaffInGroup;
|
|
62419
|
+
if (!this.firstVisibleStaff) {
|
|
62420
|
+
this.firstVisibleStaff = firstVisibleStaffInGroup;
|
|
62421
|
+
}
|
|
62422
|
+
if (onlyFirstGroup) {
|
|
62423
|
+
break;
|
|
61783
62424
|
}
|
|
61784
|
-
previousStaff = staff;
|
|
61785
62425
|
}
|
|
61786
|
-
|
|
61787
|
-
|
|
61788
|
-
|
|
62426
|
+
// ensure we add overflow if last bracket is hidden
|
|
62427
|
+
if (endSpikeOverflow) {
|
|
62428
|
+
currentY += endSpikeOverflow;
|
|
61789
62429
|
}
|
|
62430
|
+
this._contentHeight = currentY;
|
|
62431
|
+
return anyStaffVisible;
|
|
61790
62432
|
}
|
|
61791
62433
|
buildBoundingsLookup(cx, cy) {
|
|
61792
62434
|
if (this.layout.renderer.boundsLookup.isFinished) {
|
|
@@ -61820,6 +62462,9 @@
|
|
|
61820
62462
|
const masterBarBoundsLookup = new Map();
|
|
61821
62463
|
for (let i = 0; i < this.staves.length; i++) {
|
|
61822
62464
|
for (const staff of this.staves[i].staves) {
|
|
62465
|
+
if (!staff.isVisible) {
|
|
62466
|
+
continue;
|
|
62467
|
+
}
|
|
61823
62468
|
for (const renderer of staff.barRenderers) {
|
|
61824
62469
|
let masterBarBounds;
|
|
61825
62470
|
if (!masterBarBoundsLookup.has(renderer.bar.masterBar.index)) {
|
|
@@ -62130,8 +62775,9 @@
|
|
|
62130
62775
|
}
|
|
62131
62776
|
firstBarIndex = 0;
|
|
62132
62777
|
lastBarIndex = 0;
|
|
62133
|
-
createEmptyStaffSystem() {
|
|
62778
|
+
createEmptyStaffSystem(index) {
|
|
62134
62779
|
const system = new StaffSystem(this);
|
|
62780
|
+
system.index = index;
|
|
62135
62781
|
const allFactories = Environment.defaultRenderers;
|
|
62136
62782
|
const renderStaves = [];
|
|
62137
62783
|
for (let trackIndex = 0; trackIndex < this.renderer.tracks.length; trackIndex++) {
|
|
@@ -62143,7 +62789,7 @@
|
|
|
62143
62789
|
let previousStaff = undefined;
|
|
62144
62790
|
for (const factory of allFactories) {
|
|
62145
62791
|
if (this.profile.has(factory.staffId) && factory.canCreate(track, staff)) {
|
|
62146
|
-
const renderStaff = new RenderStaff(trackIndex, staff, factory);
|
|
62792
|
+
const renderStaff = new RenderStaff(system, trackIndex, staff, factory);
|
|
62147
62793
|
// insert shared effect bands at front
|
|
62148
62794
|
renderStaff.topEffectInfos.splice(0, 0, ...sharedTopEffects);
|
|
62149
62795
|
renderStaff.bottomEffectInfos.push(...sharedBottomEffects);
|
|
@@ -65301,7 +65947,7 @@
|
|
|
65301
65947
|
}
|
|
65302
65948
|
endBarIndex = startIndex + endBarIndex - 1; // map count to array index
|
|
65303
65949
|
endBarIndex = Math.min(score.masterBars.length - 1, Math.max(0, endBarIndex));
|
|
65304
|
-
this._system = this.createEmptyStaffSystem();
|
|
65950
|
+
this._system = this.createEmptyStaffSystem(0);
|
|
65305
65951
|
this._system.isLast = true;
|
|
65306
65952
|
this._system.x = this.pagePadding[0];
|
|
65307
65953
|
this._system.y = this.pagePadding[1];
|
|
@@ -65574,8 +66220,7 @@
|
|
|
65574
66220
|
this._systems = [];
|
|
65575
66221
|
let currentIndex = 0;
|
|
65576
66222
|
const maxWidth = this._maxWidth;
|
|
65577
|
-
let system = this.createEmptyStaffSystem();
|
|
65578
|
-
system.index = this._systems.length;
|
|
66223
|
+
let system = this.createEmptyStaffSystem(this._systems.length);
|
|
65579
66224
|
system.x = this.pagePadding[0];
|
|
65580
66225
|
system.y = y;
|
|
65581
66226
|
while (currentIndex < this._allMasterBarRenderers.length) {
|
|
@@ -65606,8 +66251,7 @@
|
|
|
65606
66251
|
this._fitSystem(system);
|
|
65607
66252
|
y += this._paintSystem(system, oldHeight);
|
|
65608
66253
|
// note: we do not increase currentIndex here to have it added to the next system
|
|
65609
|
-
system = this.createEmptyStaffSystem();
|
|
65610
|
-
system.index = this._systems.length;
|
|
66254
|
+
system = this.createEmptyStaffSystem(this._systems.length);
|
|
65611
66255
|
system.x = this.pagePadding[0];
|
|
65612
66256
|
system.y = y;
|
|
65613
66257
|
}
|
|
@@ -65692,8 +66336,7 @@
|
|
|
65692
66336
|
return barsPerRow;
|
|
65693
66337
|
}
|
|
65694
66338
|
_createStaffSystem(currentBarIndex, endIndex) {
|
|
65695
|
-
const system = this.createEmptyStaffSystem();
|
|
65696
|
-
system.index = this._systems.length;
|
|
66339
|
+
const system = this.createEmptyStaffSystem(this._systems.length);
|
|
65697
66340
|
const barsPerRow = this._getBarsPerSystem(system.index);
|
|
65698
66341
|
const maxWidth = this._maxWidth;
|
|
65699
66342
|
const end = endIndex + 1;
|
|
@@ -68373,16 +69016,77 @@
|
|
|
68373
69016
|
class ClefGlyph extends MusicFontGlyph {
|
|
68374
69017
|
_clef;
|
|
68375
69018
|
_clefOttava;
|
|
69019
|
+
_ottavaGlyph;
|
|
68376
69020
|
constructor(x, y, clef, clefOttava) {
|
|
68377
69021
|
super(x, y, 1, ClefGlyph._getSymbol(clef, clefOttava));
|
|
68378
69022
|
this._clef = clef;
|
|
68379
69023
|
this._clefOttava = clefOttava;
|
|
68380
69024
|
}
|
|
69025
|
+
getBoundingBoxTop() {
|
|
69026
|
+
let top = super.getBoundingBoxTop();
|
|
69027
|
+
const ottava = this._ottavaGlyph;
|
|
69028
|
+
if (ottava) {
|
|
69029
|
+
const ottavaTop = this.y + ottava.getBoundingBoxTop();
|
|
69030
|
+
top = ModelUtils.minBoundingBox(top, ottavaTop);
|
|
69031
|
+
}
|
|
69032
|
+
return top;
|
|
69033
|
+
}
|
|
69034
|
+
getBoundingBoxBottom() {
|
|
69035
|
+
let bottom = super.getBoundingBoxBottom();
|
|
69036
|
+
const ottava = this._ottavaGlyph;
|
|
69037
|
+
if (ottava) {
|
|
69038
|
+
const ottavaBottom = this.y + ottava.getBoundingBoxBottom();
|
|
69039
|
+
bottom = ModelUtils.maxBoundingBox(bottom, ottavaBottom);
|
|
69040
|
+
}
|
|
69041
|
+
return bottom;
|
|
69042
|
+
}
|
|
68381
69043
|
doLayout() {
|
|
68382
69044
|
this.center = true;
|
|
68383
69045
|
super.doLayout();
|
|
68384
69046
|
this.width = this.renderer.smuflMetrics.glyphWidths.get(MusicFontSymbol.GClef);
|
|
68385
69047
|
this.offsetX = this.width / 2;
|
|
69048
|
+
this._ottavaGlyph = undefined;
|
|
69049
|
+
switch (this._clef) {
|
|
69050
|
+
case Clef.C3:
|
|
69051
|
+
case Clef.C4:
|
|
69052
|
+
switch (this._clefOttava) {
|
|
69053
|
+
case Ottavia._8vb:
|
|
69054
|
+
return;
|
|
69055
|
+
}
|
|
69056
|
+
break;
|
|
69057
|
+
case Clef.F4:
|
|
69058
|
+
case Clef.G2:
|
|
69059
|
+
return;
|
|
69060
|
+
}
|
|
69061
|
+
let ottavaSymbol;
|
|
69062
|
+
let top = false;
|
|
69063
|
+
switch (this._clefOttava) {
|
|
69064
|
+
case Ottavia._15ma:
|
|
69065
|
+
ottavaSymbol = MusicFontSymbol.Clef15;
|
|
69066
|
+
top = true;
|
|
69067
|
+
break;
|
|
69068
|
+
case Ottavia._8va:
|
|
69069
|
+
ottavaSymbol = MusicFontSymbol.Clef8;
|
|
69070
|
+
top = true;
|
|
69071
|
+
break;
|
|
69072
|
+
case Ottavia._8vb:
|
|
69073
|
+
ottavaSymbol = MusicFontSymbol.Clef8;
|
|
69074
|
+
break;
|
|
69075
|
+
case Ottavia._15mb:
|
|
69076
|
+
ottavaSymbol = MusicFontSymbol.Clef15;
|
|
69077
|
+
break;
|
|
69078
|
+
default:
|
|
69079
|
+
return;
|
|
69080
|
+
}
|
|
69081
|
+
const ottavaX = this.width / 2;
|
|
69082
|
+
const ottavaY = top
|
|
69083
|
+
? this.renderer.smuflMetrics.glyphTop.get(this.symbol)
|
|
69084
|
+
: this.renderer.smuflMetrics.glyphBottom.get(this.symbol) -
|
|
69085
|
+
this.renderer.smuflMetrics.glyphHeights.get(ottavaSymbol);
|
|
69086
|
+
this._ottavaGlyph = new MusicFontGlyph(ottavaX, -ottavaY, 1, ottavaSymbol);
|
|
69087
|
+
this._ottavaGlyph.center = true;
|
|
69088
|
+
this._ottavaGlyph.renderer = this.renderer;
|
|
69089
|
+
this._ottavaGlyph.doLayout();
|
|
68386
69090
|
}
|
|
68387
69091
|
static _getSymbol(clef, clefOttava) {
|
|
68388
69092
|
switch (clef) {
|
|
@@ -68430,44 +69134,10 @@
|
|
|
68430
69134
|
const _ = ElementStyleHelper.bar(canvas, BarSubElement.StandardNotationClef, this.renderer.bar);
|
|
68431
69135
|
try {
|
|
68432
69136
|
super.paint(cx, cy, canvas);
|
|
68433
|
-
|
|
68434
|
-
|
|
68435
|
-
|
|
68436
|
-
switch (this._clefOttava) {
|
|
68437
|
-
case Ottavia._8vb:
|
|
68438
|
-
return;
|
|
68439
|
-
}
|
|
68440
|
-
break;
|
|
68441
|
-
case Clef.F4:
|
|
68442
|
-
case Clef.G2:
|
|
68443
|
-
return;
|
|
68444
|
-
}
|
|
68445
|
-
let ottavaGlyph;
|
|
68446
|
-
let top = false;
|
|
68447
|
-
switch (this._clefOttava) {
|
|
68448
|
-
case Ottavia._15ma:
|
|
68449
|
-
ottavaGlyph = MusicFontSymbol.Clef15;
|
|
68450
|
-
top = true;
|
|
68451
|
-
break;
|
|
68452
|
-
case Ottavia._8va:
|
|
68453
|
-
ottavaGlyph = MusicFontSymbol.Clef8;
|
|
68454
|
-
top = true;
|
|
68455
|
-
break;
|
|
68456
|
-
case Ottavia._8vb:
|
|
68457
|
-
ottavaGlyph = MusicFontSymbol.Clef8;
|
|
68458
|
-
break;
|
|
68459
|
-
case Ottavia._15mb:
|
|
68460
|
-
ottavaGlyph = MusicFontSymbol.Clef15;
|
|
68461
|
-
break;
|
|
68462
|
-
default:
|
|
68463
|
-
return;
|
|
69137
|
+
const ottava = this._ottavaGlyph;
|
|
69138
|
+
if (ottava) {
|
|
69139
|
+
ottava.paint(cx + this.x, cy + this.y, canvas);
|
|
68464
69140
|
}
|
|
68465
|
-
const ottavaX = this.width / 2;
|
|
68466
|
-
const ottavaY = top
|
|
68467
|
-
? this.renderer.smuflMetrics.glyphTop.get(this.symbol)
|
|
68468
|
-
: this.renderer.smuflMetrics.glyphBottom.get(this.symbol) -
|
|
68469
|
-
this.renderer.smuflMetrics.glyphHeights.get(ottavaGlyph);
|
|
68470
|
-
CanvasHelper.fillMusicFontSymbolSafe(canvas, cx + this.x + ottavaX, cy + this.y - ottavaY, 1, ottavaGlyph, true);
|
|
68471
69141
|
}
|
|
68472
69142
|
finally {
|
|
68473
69143
|
_?.[Symbol.dispose]?.();
|