lexgui 0.6.11 → 0.7.0
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/README.md +14 -9
- package/build/{components → extensions}/audio.js +11 -11
- package/build/{components → extensions}/codeeditor.js +109 -74
- package/build/{components → extensions}/docmaker.js +10 -3
- package/build/{components → extensions}/imui.js +19 -12
- package/build/{components → extensions}/nodegraph.js +1 -1
- package/build/{components → extensions}/timeline.js +150 -94
- package/build/{components → extensions}/videoeditor.js +1 -1
- package/build/lexgui-docs.css +9 -9
- package/build/lexgui.css +489 -223
- package/build/lexgui.js +1771 -777
- package/build/lexgui.min.css +2 -2
- package/build/lexgui.min.js +1 -1
- package/build/lexgui.module.js +1803 -809
- package/build/lexgui.module.min.js +1 -1
- package/changelog.md +90 -21
- package/demo.js +52 -32
- package/examples/{all_widgets.html → all-components.html} +22 -4
- package/examples/{area_tabs.html → area-tabs.html} +3 -3
- package/examples/{asset_view.html → asset-view.html} +3 -3
- package/examples/{code_editor.html → code-editor.html} +4 -4
- package/examples/dialogs.html +3 -3
- package/examples/editor.html +27 -18
- package/examples/{immediate_ui.html → immediate-ui.html} +3 -3
- package/examples/index.html +8 -8
- package/examples/{node_graph.html → node-graph.html} +3 -3
- package/examples/previews/all-components.png +0 -0
- package/examples/previews/area-tabs.png +0 -0
- package/examples/previews/asset-view.png +0 -0
- package/examples/previews/code-editor.png +0 -0
- package/examples/previews/dialogs.png +0 -0
- package/examples/previews/editor.png +0 -0
- package/examples/previews/node-graph.png +0 -0
- package/examples/previews/side-bar.png +0 -0
- package/examples/previews/timeline.png +0 -0
- package/examples/{side_bar.html → side-bar.html} +3 -3
- package/examples/timeline.html +5 -5
- package/examples/{video_editor.html → video-editor.html} +3 -3
- package/examples/{video_editor2.html → video-editor2.html} +3 -3
- package/package.json +2 -2
- package/examples/previews/all_widgets.png +0 -0
- package/examples/previews/area_tabs.png +0 -0
- package/examples/previews/asset_view.png +0 -0
- package/examples/previews/code_editor.png +0 -0
- package/examples/previews/node_graph.png +0 -0
- package/examples/previews/side_bar.png +0 -0
|
@@ -4,7 +4,7 @@ if(!LX) {
|
|
|
4
4
|
throw("lexgui.js missing!");
|
|
5
5
|
}
|
|
6
6
|
|
|
7
|
-
LX.
|
|
7
|
+
LX.extensions.push( 'Timeline' );
|
|
8
8
|
|
|
9
9
|
/**
|
|
10
10
|
* @class Timeline
|
|
@@ -103,8 +103,8 @@ class Timeline {
|
|
|
103
103
|
this.selectedItems = []; // [trackInfo, "groupId"], contains the visible items (tracks or groups) of the timeline
|
|
104
104
|
this.leftPanel = left.addPanel( { className: 'lextimelinepanel', width: "100%", height: "100%" } );
|
|
105
105
|
this.trackTreesPanel = null;
|
|
106
|
-
this.
|
|
107
|
-
this.
|
|
106
|
+
this.trackTreesComponent = null;
|
|
107
|
+
this.lastTrackTreesComponentOffset = 0; // this.trackTreesComponent.innerTree.domEl.offsetTop - canvas.offsetTop. Check draw()
|
|
108
108
|
this.updateLeftPanel();
|
|
109
109
|
|
|
110
110
|
if(this.uniqueID != '') {
|
|
@@ -196,6 +196,7 @@ class Timeline {
|
|
|
196
196
|
signal: "@on_set_time_" + this.uniqueID,
|
|
197
197
|
step: 0.01, min: 0, precision: 3,
|
|
198
198
|
skipSlider: true,
|
|
199
|
+
skipReset: true,
|
|
199
200
|
nameWidth: "auto"
|
|
200
201
|
});
|
|
201
202
|
|
|
@@ -205,6 +206,7 @@ class Timeline {
|
|
|
205
206
|
units: "s",
|
|
206
207
|
step: 0.01, min: 0,
|
|
207
208
|
signal: "@on_set_duration_" + this.uniqueID,
|
|
209
|
+
skipReset: true,
|
|
208
210
|
nameWidth: "auto"
|
|
209
211
|
});
|
|
210
212
|
|
|
@@ -265,8 +267,8 @@ class Timeline {
|
|
|
265
267
|
const panel = this.leftPanel;
|
|
266
268
|
|
|
267
269
|
panel.sameLine( 2 );
|
|
268
|
-
let
|
|
269
|
-
let title =
|
|
270
|
+
let titleComponent = panel.addTitle( "Tracks", { style: { background: "none"}, className: "fg-secondary text-lg px-4"} );
|
|
271
|
+
let title = titleComponent.root;
|
|
270
272
|
|
|
271
273
|
if( !this.disableNewTracks )
|
|
272
274
|
{
|
|
@@ -291,7 +293,7 @@ class Timeline {
|
|
|
291
293
|
{
|
|
292
294
|
treeTracks = this.generateSelectedItemsTreeData();
|
|
293
295
|
}
|
|
294
|
-
this.
|
|
296
|
+
this.trackTreesComponent = p.addTree(null, treeTracks, {filter: false, rename: false, draggable: false, onevent: (e) => {
|
|
295
297
|
switch(e.type) {
|
|
296
298
|
case LX.TreeEvent.NODE_SELECTED:
|
|
297
299
|
if (e.node.trackData){
|
|
@@ -308,8 +310,8 @@ class Timeline {
|
|
|
308
310
|
}
|
|
309
311
|
}});
|
|
310
312
|
// setting a name in the addTree function adds an undesired node
|
|
311
|
-
this.
|
|
312
|
-
p.
|
|
313
|
+
this.trackTreesComponent.name = "tracksTrees";
|
|
314
|
+
p.components[this.trackTreesComponent.name] = this.trackTreesComponent;
|
|
313
315
|
|
|
314
316
|
this.trackTreesPanel = p;
|
|
315
317
|
panel.attach( p.root );
|
|
@@ -374,8 +376,8 @@ class Timeline {
|
|
|
374
376
|
return [];
|
|
375
377
|
}
|
|
376
378
|
|
|
377
|
-
const startY = minY - this.
|
|
378
|
-
const endY = maxY - this.
|
|
379
|
+
const startY = minY - this.lastTrackTreesComponentOffset + this.currentScrollInPixels;
|
|
380
|
+
const endY = maxY - this.lastTrackTreesComponentOffset + this.currentScrollInPixels;
|
|
379
381
|
|
|
380
382
|
const startIdx = Math.max( 0, Math.floor( startY / this.trackHeight ) );
|
|
381
383
|
const endIdx = Math.min( elements.length-1, Math.floor( endY / this.trackHeight ) ) + 1;
|
|
@@ -400,13 +402,9 @@ class Timeline {
|
|
|
400
402
|
*/
|
|
401
403
|
setAnimationClip( animation, needsToProcess = true ) {
|
|
402
404
|
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
if ( this.unHoverAll ){
|
|
407
|
-
this.unHoverAll();
|
|
408
|
-
}
|
|
409
|
-
this.unSelectAllTracks();
|
|
405
|
+
this.deselectAllElements();
|
|
406
|
+
this.deselectAllTracks();
|
|
407
|
+
|
|
410
408
|
this.selectedItems = [];
|
|
411
409
|
|
|
412
410
|
this.clearState();
|
|
@@ -499,7 +497,7 @@ class Timeline {
|
|
|
499
497
|
|
|
500
498
|
// Content
|
|
501
499
|
const topMargin = this.topMargin;
|
|
502
|
-
const treeOffset = this.
|
|
500
|
+
const treeOffset = this.lastTrackTreesComponentOffset;
|
|
503
501
|
const line_height = this.trackHeight;
|
|
504
502
|
|
|
505
503
|
//fill track lines
|
|
@@ -547,12 +545,12 @@ class Timeline {
|
|
|
547
545
|
const w = ctx.canvas.width;
|
|
548
546
|
const h = ctx.canvas.height;
|
|
549
547
|
|
|
550
|
-
const scrollableHeight = this.
|
|
548
|
+
const scrollableHeight = this.trackTreesComponent.root.scrollHeight;
|
|
551
549
|
// tree has gaps of 0.25rem (4px) inbetween entries but not in the beginning nor ending. Move half gap upwards.
|
|
552
|
-
const treeOffset = this.
|
|
550
|
+
const treeOffset = this.lastTrackTreesComponentOffset = this.trackTreesComponent.innerTree.domEl.offsetTop - this.canvas.offsetTop -2;
|
|
553
551
|
|
|
554
552
|
if ( this.trackTreesPanel.root.scrollHeight > 0 ){
|
|
555
|
-
const ul = this.
|
|
553
|
+
const ul = this.trackTreesComponent.innerTree.domEl.children[0];
|
|
556
554
|
this.trackHeight = ul.children.length < 1 ? 25 : ((ul.offsetHeight+4) / ul.children.length);
|
|
557
555
|
}
|
|
558
556
|
|
|
@@ -785,7 +783,7 @@ class Timeline {
|
|
|
785
783
|
}
|
|
786
784
|
|
|
787
785
|
}
|
|
788
|
-
else if( (h-this.topMargin) < this.
|
|
786
|
+
else if( (h-this.topMargin) < this.trackTreesComponent.root.scrollHeight)
|
|
789
787
|
{
|
|
790
788
|
this.trackTreesPanel.root.scrollTop += e.deltaY; // wheel deltaY
|
|
791
789
|
}
|
|
@@ -832,11 +830,13 @@ class Timeline {
|
|
|
832
830
|
this.movingKeys = false;
|
|
833
831
|
this.timeBeforeMove = null;
|
|
834
832
|
this.boxSelection = false; // after mouseup
|
|
835
|
-
this.
|
|
833
|
+
this.deselectAllTracks();
|
|
836
834
|
}
|
|
837
835
|
|
|
838
836
|
|
|
839
837
|
if( e.type == "mousedown") {
|
|
838
|
+
window.getSelection().empty(); // if canvas DOM is selected, dragging does not work properly. Deselect it
|
|
839
|
+
|
|
840
840
|
// e.preventDefault();
|
|
841
841
|
|
|
842
842
|
this.clickTime = LX.getTime();
|
|
@@ -852,7 +852,7 @@ class Timeline {
|
|
|
852
852
|
this.grabbingTimeBar = true;
|
|
853
853
|
this.setTime(time);
|
|
854
854
|
}
|
|
855
|
-
else if( (h-this.topMargin) < this.
|
|
855
|
+
else if( (h-this.topMargin) < this.trackTreesComponent.root.scrollHeight && x > w - 10 ) { // grabbing scroll bar
|
|
856
856
|
this.grabbing = true;
|
|
857
857
|
this.grabbingScroll = true;
|
|
858
858
|
}
|
|
@@ -972,7 +972,7 @@ class Timeline {
|
|
|
972
972
|
setState(state, skipCallback = false) {
|
|
973
973
|
this.playing = state;
|
|
974
974
|
|
|
975
|
-
this.header.
|
|
975
|
+
this.header.components.playBtn.setState(this.playing, true);
|
|
976
976
|
|
|
977
977
|
if(this.onStateChange && !skipCallback) {
|
|
978
978
|
this.onStateChange(this.playing);
|
|
@@ -988,9 +988,9 @@ class Timeline {
|
|
|
988
988
|
setLoopMode(loopState, skipCallback = false){
|
|
989
989
|
this.loop = loopState;
|
|
990
990
|
if ( this.loop ){
|
|
991
|
-
this.header.
|
|
991
|
+
this.header.components.loopBtn.root.children[0].classList.add("selected");
|
|
992
992
|
}else{
|
|
993
|
-
this.header.
|
|
993
|
+
this.header.components.loopBtn.root.children[0].classList.remove("selected")
|
|
994
994
|
}
|
|
995
995
|
if( this.onChangeLoopMode && !skipCallback ){
|
|
996
996
|
this.onChangeLoopMode( this.loop );
|
|
@@ -1003,7 +1003,7 @@ class Timeline {
|
|
|
1003
1003
|
* If not a track, trackData will be undefined
|
|
1004
1004
|
*/
|
|
1005
1005
|
getVisibleItems(){
|
|
1006
|
-
return this.
|
|
1006
|
+
return this.trackTreesComponent.innerTree.domEl.children[0].children; // children of 'ul'
|
|
1007
1007
|
}
|
|
1008
1008
|
|
|
1009
1009
|
/**
|
|
@@ -1071,7 +1071,7 @@ class Timeline {
|
|
|
1071
1071
|
* Only affects render visualisation
|
|
1072
1072
|
* @method selectTrack
|
|
1073
1073
|
* @param {int} trackIdx
|
|
1074
|
-
* // NOTE: to select a track from outside of the timeline, a this.
|
|
1074
|
+
* // NOTE: to select a track from outside of the timeline, a this.trackTreesComponent.innerTree.select(item) needs to be called.
|
|
1075
1075
|
*/
|
|
1076
1076
|
selectTrack( trackIdx ) {
|
|
1077
1077
|
|
|
@@ -1079,7 +1079,7 @@ class Timeline {
|
|
|
1079
1079
|
return;
|
|
1080
1080
|
}
|
|
1081
1081
|
|
|
1082
|
-
this.
|
|
1082
|
+
this.deselectAllTracks();
|
|
1083
1083
|
|
|
1084
1084
|
let track = this.animationClip.tracks[ trackIdx ];
|
|
1085
1085
|
track.isSelected = true;
|
|
@@ -1090,7 +1090,7 @@ class Timeline {
|
|
|
1090
1090
|
}
|
|
1091
1091
|
|
|
1092
1092
|
// Only affects render visualisation
|
|
1093
|
-
|
|
1093
|
+
deselectAllTracks() {
|
|
1094
1094
|
|
|
1095
1095
|
if( !this.animationClip ){
|
|
1096
1096
|
return;
|
|
@@ -1102,7 +1102,7 @@ class Timeline {
|
|
|
1102
1102
|
}
|
|
1103
1103
|
}
|
|
1104
1104
|
|
|
1105
|
-
|
|
1105
|
+
deselectAllElements(){
|
|
1106
1106
|
|
|
1107
1107
|
}
|
|
1108
1108
|
|
|
@@ -1149,7 +1149,7 @@ class Timeline {
|
|
|
1149
1149
|
|
|
1150
1150
|
if (!toBeShown.length){ return false; }
|
|
1151
1151
|
|
|
1152
|
-
this.
|
|
1152
|
+
this.deselectAllElements();
|
|
1153
1153
|
|
|
1154
1154
|
const combinedState = toBeShown.pop();
|
|
1155
1155
|
const combinedStateToStore = [];
|
|
@@ -1247,7 +1247,7 @@ class Timeline {
|
|
|
1247
1247
|
|
|
1248
1248
|
|
|
1249
1249
|
/**
|
|
1250
|
-
* This functions uses the selectedItems and generates the data that will feed the LX.Tree
|
|
1250
|
+
* This functions uses the selectedItems and generates the data that will feed the LX.Tree Component.
|
|
1251
1251
|
* This function is used by updateLeftPanel. Some timelines might allow grouping of tracks. Such timelines may overwrite this function
|
|
1252
1252
|
* WARNING: track entries MUST have an attribute of 'trackData' with the track info
|
|
1253
1253
|
* @returns lexgui tree data as expecte for the creation of a tree
|
|
@@ -1555,8 +1555,8 @@ class KeyFramesTimeline extends Timeline {
|
|
|
1555
1555
|
}
|
|
1556
1556
|
|
|
1557
1557
|
// OVERRIDE
|
|
1558
|
-
|
|
1559
|
-
this.
|
|
1558
|
+
deselectAllElements(){
|
|
1559
|
+
this.deselectAllKeyFrames();
|
|
1560
1560
|
this.unHoverAll();
|
|
1561
1561
|
}
|
|
1562
1562
|
|
|
@@ -1568,7 +1568,7 @@ class KeyFramesTimeline extends Timeline {
|
|
|
1568
1568
|
changeSelectedItems( itemsToAdd = null, itemsToRemove = null, skipCallback = false ) {
|
|
1569
1569
|
|
|
1570
1570
|
// TODO: maybe make this un-functions more general
|
|
1571
|
-
this.
|
|
1571
|
+
this.deselectAllKeyFrames();
|
|
1572
1572
|
this.unHoverAll();
|
|
1573
1573
|
|
|
1574
1574
|
const tracks = this.animationClip.tracks;
|
|
@@ -1717,7 +1717,7 @@ class KeyFramesTimeline extends Timeline {
|
|
|
1717
1717
|
const keyFrameIdx = this.getCurrentKeyFrame( track, this.xToTime( localX ), this.secondsPerPixel * 5 );
|
|
1718
1718
|
if ( keyFrameIdx > -1 ){
|
|
1719
1719
|
track.selected[keyFrameIdx] ?
|
|
1720
|
-
this.
|
|
1720
|
+
this.deselectKeyFrame(track.trackIdx, keyFrameIdx) :
|
|
1721
1721
|
this.processSelectionKeyFrame( track.trackIdx, keyFrameIdx, true );
|
|
1722
1722
|
}
|
|
1723
1723
|
}
|
|
@@ -1742,10 +1742,10 @@ class KeyFramesTimeline extends Timeline {
|
|
|
1742
1742
|
else if( !this.movingKeys && !discard ){ // if not moving timeline and not adding keyframes through e.shiftkey (just a click)
|
|
1743
1743
|
|
|
1744
1744
|
if ( this.lastKeyFramesSelected.length ){
|
|
1745
|
-
if (this.
|
|
1746
|
-
this.
|
|
1745
|
+
if (this.onDeselectKeyFrames){
|
|
1746
|
+
this.onDeselectKeyFrames( this.lastKeyFramesSelected );
|
|
1747
1747
|
}
|
|
1748
|
-
this.
|
|
1748
|
+
this.deselectAllKeyFrames();
|
|
1749
1749
|
}
|
|
1750
1750
|
if (track){
|
|
1751
1751
|
const keyFrameIndex = this.getCurrentKeyFrame( track, this.xToTime( localX ), this.secondsPerPixel * 5 );
|
|
@@ -2129,27 +2129,43 @@ class KeyFramesTimeline extends Timeline {
|
|
|
2129
2129
|
//draw lines
|
|
2130
2130
|
ctx.strokeStyle = "white";
|
|
2131
2131
|
ctx.beginPath();
|
|
2132
|
-
for(let j = 0; j < keyframes.length; ++j){
|
|
2133
2132
|
|
|
2134
|
-
|
|
2135
|
-
let
|
|
2136
|
-
let
|
|
2137
|
-
|
|
2133
|
+
if ( keyframes.length > 1){
|
|
2134
|
+
let startPosX = this.timeToX( keyframes[0] );
|
|
2135
|
+
let startValue = values[0];
|
|
2136
|
+
startValue = ((startValue - valueRange[0]) / (valueRange[1] - valueRange[0])) * (-displayRange) + (trackHeight - defaultPointSize); // normalize and offset
|
|
2137
|
+
ctx.moveTo( startPosX, startValue );
|
|
2138
2138
|
|
|
2139
|
-
|
|
2140
|
-
ctx.moveTo( keyframePosX, value );
|
|
2141
|
-
continue;
|
|
2142
|
-
}
|
|
2139
|
+
for(let j = 1; j < keyframes.length; ++j){
|
|
2143
2140
|
|
|
2144
|
-
|
|
2145
|
-
|
|
2146
|
-
|
|
2147
|
-
|
|
2148
|
-
|
|
2141
|
+
let time = keyframes[j];
|
|
2142
|
+
let keyframePosX = this.timeToX( time );
|
|
2143
|
+
let value = values[j];
|
|
2144
|
+
value = ((value - valueRange[0]) / (valueRange[1] - valueRange[0])) * (-displayRange) + (trackHeight - defaultPointSize); // normalize and offset
|
|
2145
|
+
|
|
2146
|
+
if( time < startTime ){
|
|
2147
|
+
ctx.moveTo( keyframePosX, value );
|
|
2148
|
+
continue;
|
|
2149
|
+
}
|
|
2150
|
+
|
|
2151
|
+
if ( time > endTime ){
|
|
2152
|
+
let lastKeyframePosX = this.timeToX( keyframes[j-1] );
|
|
2153
|
+
let dt = keyframePosX - lastKeyframePosX;
|
|
2154
|
+
if ( dt > 0 ){
|
|
2155
|
+
let lastValue = values[j-1];
|
|
2156
|
+
lastValue = ((lastValue - valueRange[0]) / (valueRange[1] - valueRange[0])) * (-displayRange) + (trackHeight - defaultPointSize); // normalize and offset
|
|
2157
|
+
let f = (this.timeToX( endTime ) - lastKeyframePosX) / dt;
|
|
2158
|
+
ctx.lineTo( lastKeyframePosX + dt * f, lastValue * (1-f) + value * f );
|
|
2159
|
+
}
|
|
2160
|
+
break; //end loop, but print line
|
|
2161
|
+
}
|
|
2162
|
+
|
|
2163
|
+
//convert to timeline track range
|
|
2164
|
+
ctx.lineTo( keyframePosX, value );
|
|
2149
2165
|
}
|
|
2166
|
+
ctx.stroke();
|
|
2150
2167
|
}
|
|
2151
|
-
|
|
2152
|
-
|
|
2168
|
+
|
|
2153
2169
|
//draw points
|
|
2154
2170
|
ctx.fillStyle = Timeline.KEYFRAME_COLOR;
|
|
2155
2171
|
for(let j = 0; j < keyframes.length; ++j)
|
|
@@ -2604,7 +2620,7 @@ class KeyFramesTimeline extends Timeline {
|
|
|
2604
2620
|
if ( !this.clipboard.keyframes ){ return false; }
|
|
2605
2621
|
|
|
2606
2622
|
this.unHoverAll();
|
|
2607
|
-
this.
|
|
2623
|
+
this.deselectAllKeyFrames();
|
|
2608
2624
|
|
|
2609
2625
|
let clipboardTracks = this.clipboard.keyframes;
|
|
2610
2626
|
let globalStart = Infinity;
|
|
@@ -2933,16 +2949,16 @@ class KeyFramesTimeline extends Timeline {
|
|
|
2933
2949
|
return h;
|
|
2934
2950
|
}
|
|
2935
2951
|
|
|
2936
|
-
|
|
2952
|
+
deselectAllKeyFrames() {
|
|
2937
2953
|
|
|
2938
2954
|
for(let [trackIdx, keyIndex] of this.lastKeyFramesSelected) {
|
|
2939
2955
|
this.animationClip.tracks[trackIdx].selected[keyIndex] = false;
|
|
2940
2956
|
}
|
|
2941
2957
|
|
|
2942
|
-
// Something has been
|
|
2943
|
-
const
|
|
2958
|
+
// Something has been deselected
|
|
2959
|
+
const deselected = this.lastKeyFramesSelected.length > 0;
|
|
2944
2960
|
this.lastKeyFramesSelected.length = 0;
|
|
2945
|
-
return
|
|
2961
|
+
return deselected;
|
|
2946
2962
|
}
|
|
2947
2963
|
|
|
2948
2964
|
isKeyFrameSelected( track, index ) {
|
|
@@ -2981,7 +2997,7 @@ class KeyFramesTimeline extends Timeline {
|
|
|
2981
2997
|
return selection;
|
|
2982
2998
|
}
|
|
2983
2999
|
|
|
2984
|
-
|
|
3000
|
+
deselectKeyFrame( trackIdx, frameIdx ){
|
|
2985
3001
|
const track = this.animationClip.tracks[trackIdx];
|
|
2986
3002
|
if( track.locked || !track.active || !track.selected[frameIdx] )
|
|
2987
3003
|
return false;
|
|
@@ -3017,7 +3033,7 @@ class KeyFramesTimeline extends Timeline {
|
|
|
3017
3033
|
return;
|
|
3018
3034
|
|
|
3019
3035
|
if(!multipleSelection) {
|
|
3020
|
-
this.
|
|
3036
|
+
this.deselectAllKeyFrames();
|
|
3021
3037
|
}
|
|
3022
3038
|
|
|
3023
3039
|
this.selectKeyFrame(trackIdx, keyFrameIndex);
|
|
@@ -3039,7 +3055,7 @@ class KeyFramesTimeline extends Timeline {
|
|
|
3039
3055
|
}
|
|
3040
3056
|
|
|
3041
3057
|
this.unHoverAll();
|
|
3042
|
-
this.
|
|
3058
|
+
this.deselectAllKeyFrames();
|
|
3043
3059
|
|
|
3044
3060
|
this.saveState(track.trackIdx);
|
|
3045
3061
|
|
|
@@ -3139,9 +3155,30 @@ class ClipsTimeline extends Timeline {
|
|
|
3139
3155
|
track.hovered = (new Array(numClips)).fill(false);
|
|
3140
3156
|
}
|
|
3141
3157
|
|
|
3158
|
+
// sanity check. Also done in addClip
|
|
3159
|
+
for( let i = 0; i < track.clips.length; ++i ){
|
|
3160
|
+
track.clips[i].active = track.clips[i].active ?? true;
|
|
3161
|
+
}
|
|
3142
3162
|
return track;
|
|
3143
3163
|
}
|
|
3144
3164
|
|
|
3165
|
+
// provides an base example of a proper clip
|
|
3166
|
+
instantiateClip(options = {}){
|
|
3167
|
+
return {
|
|
3168
|
+
id: options.id ?? (options.name ?? "clip"),
|
|
3169
|
+
|
|
3170
|
+
start: options.start ?? 0,
|
|
3171
|
+
duration: options.duration ?? 1,
|
|
3172
|
+
fadein: options.fadein ?? undefined,
|
|
3173
|
+
fadeout: options.fadeout ?? undefined,
|
|
3174
|
+
|
|
3175
|
+
clipColor: options.clipColor ?? LX.getThemeColor("global-color-accent"),
|
|
3176
|
+
fadeColor: options.fadeColor ?? null,
|
|
3177
|
+
active: options.active ?? true,
|
|
3178
|
+
trackIdx: -1, // filled by addClip
|
|
3179
|
+
}
|
|
3180
|
+
|
|
3181
|
+
}
|
|
3145
3182
|
// use default updateleftpanel
|
|
3146
3183
|
// generateSelectedItemsTreeData(){}
|
|
3147
3184
|
|
|
@@ -3171,8 +3208,8 @@ class ClipsTimeline extends Timeline {
|
|
|
3171
3208
|
}
|
|
3172
3209
|
|
|
3173
3210
|
// OVERRIDE
|
|
3174
|
-
|
|
3175
|
-
this.
|
|
3211
|
+
deselectAllElements(){
|
|
3212
|
+
this.deselectAllClips();
|
|
3176
3213
|
this.unHoverAll();
|
|
3177
3214
|
}
|
|
3178
3215
|
|
|
@@ -3183,7 +3220,7 @@ class ClipsTimeline extends Timeline {
|
|
|
3183
3220
|
changeSelectedItems( ) {
|
|
3184
3221
|
|
|
3185
3222
|
// TODO: maybe make this un-functions more general
|
|
3186
|
-
this.
|
|
3223
|
+
this.deselectAllClips();
|
|
3187
3224
|
this.unHoverAll();
|
|
3188
3225
|
|
|
3189
3226
|
this.selectedItems = this.animationClip.tracks.slice();
|
|
@@ -3214,7 +3251,7 @@ class ClipsTimeline extends Timeline {
|
|
|
3214
3251
|
let clipIndex = this.getClipOnTime( track, this.xToTime( localX ), this.secondsPerPixel * 5 );
|
|
3215
3252
|
if ( clipIndex > -1 ){
|
|
3216
3253
|
track.selected[clipIndex] ?
|
|
3217
|
-
this.
|
|
3254
|
+
this.deselectClip( track.trackIdx, clipIndex ) :
|
|
3218
3255
|
this.selectClip( track.trackIdx, clipIndex, false );
|
|
3219
3256
|
}
|
|
3220
3257
|
}
|
|
@@ -3302,13 +3339,16 @@ class ClipsTimeline extends Timeline {
|
|
|
3302
3339
|
this.movingKeys = true;
|
|
3303
3340
|
}
|
|
3304
3341
|
else if( !track || track && this.getClipOnTime(track, time, 0.001) == -1) { // clicked on empty space
|
|
3305
|
-
this.
|
|
3306
|
-
|
|
3307
|
-
this.onSelectClip
|
|
3342
|
+
if ( this.lastClipsSelected.length ){
|
|
3343
|
+
this.deselectAllClips();
|
|
3344
|
+
if(this.onSelectClip){
|
|
3345
|
+
this.onSelectClip(null);
|
|
3346
|
+
}
|
|
3347
|
+
}
|
|
3308
3348
|
}
|
|
3309
3349
|
else if (track && (this.dragClipMode == "duration" || this.dragClipMode == "fadein" || this.dragClipMode == "fadeout" )) { // clicked while mouse was over fadeIn, fadeOut, duration
|
|
3310
3350
|
const clipIdx = this.getClipOnTime(track, this.xToTime(localX), 0.001);
|
|
3311
|
-
this.selectClip( track.trackIdx, clipIdx ); // select current clip if any (
|
|
3351
|
+
this.selectClip( track.trackIdx, clipIdx ); // select current clip if any (deselect others)
|
|
3312
3352
|
if ( this.lastClipsSelected.length ){
|
|
3313
3353
|
this.saveState(track.trackIdx);
|
|
3314
3354
|
}
|
|
@@ -3362,7 +3402,7 @@ class ClipsTimeline extends Timeline {
|
|
|
3362
3402
|
else if ( this.dragClipMode == "move" && this.lastClipsSelected.length ) { // move clips
|
|
3363
3403
|
//*********** WARNING: RELIES ON SORTED lastClipsSelected ***********
|
|
3364
3404
|
|
|
3365
|
-
const treeOffset = this.
|
|
3405
|
+
const treeOffset = this.lastTrackTreesComponentOffset;
|
|
3366
3406
|
let newTrackClipsMove = Math.floor( (e.localY - treeOffset) / this.trackHeight );
|
|
3367
3407
|
|
|
3368
3408
|
// move clips vertically
|
|
@@ -3621,7 +3661,7 @@ class ClipsTimeline extends Timeline {
|
|
|
3621
3661
|
|
|
3622
3662
|
if ( track ){
|
|
3623
3663
|
const clipIdx = this.getClipOnTime(track, this.xToTime(localX), 0.001);
|
|
3624
|
-
this.selectClip(track.trackIdx, clipIdx); //
|
|
3664
|
+
this.selectClip(track.trackIdx, clipIdx); // deselect and try to select clip in localX, if any
|
|
3625
3665
|
}
|
|
3626
3666
|
}
|
|
3627
3667
|
|
|
@@ -3737,14 +3777,14 @@ class ClipsTimeline extends Timeline {
|
|
|
3737
3777
|
// Overwrite clip color state depending on its state
|
|
3738
3778
|
ctx.globalAlpha = 1;
|
|
3739
3779
|
ctx.fillStyle = clip.clipColor || (track.hovered[j] ? Timeline.KEYFRAME_COLOR_HOVERED : (track.selected[j] ? Timeline.TRACK_SELECTED : Timeline.KEYFRAME_COLOR));
|
|
3740
|
-
if(!this.active || !track.active) {
|
|
3780
|
+
if(!this.active || !track.active || !clip.active) {
|
|
3741
3781
|
ctx.fillStyle = Timeline.KEYFRAME_COLOR_INACTIVE;
|
|
3742
3782
|
}
|
|
3743
3783
|
|
|
3744
3784
|
// Draw clip background
|
|
3745
3785
|
ctx.roundRect( x, y + offset, w, trackHeight , 5, true);
|
|
3746
3786
|
|
|
3747
|
-
if(this.active && track.active) {
|
|
3787
|
+
if(this.active && track.active && clip.active) {
|
|
3748
3788
|
|
|
3749
3789
|
ctx.fillStyle = clip.fadeColor ?? "#0004";
|
|
3750
3790
|
|
|
@@ -3822,6 +3862,8 @@ class ClipsTimeline extends Timeline {
|
|
|
3822
3862
|
addClip( clip, trackIdx = -1, offsetTime = 0, searchStartTrackIdx = 0 ) {
|
|
3823
3863
|
if ( !this.animationClip ){ return -1; }
|
|
3824
3864
|
|
|
3865
|
+
this.deselectAllElements(); // TODO: consider adjusting values of hovered and selected instead of deselecting everything
|
|
3866
|
+
|
|
3825
3867
|
// Update clip information
|
|
3826
3868
|
let newStart = clip.start + offsetTime;
|
|
3827
3869
|
if(clip.fadein != undefined)
|
|
@@ -3830,6 +3872,9 @@ class ClipsTimeline extends Timeline {
|
|
|
3830
3872
|
clip.fadeout += (newStart - clip.start);
|
|
3831
3873
|
clip.start = newStart;
|
|
3832
3874
|
|
|
3875
|
+
// sanity check
|
|
3876
|
+
clip.active = clip.active ?? true;
|
|
3877
|
+
|
|
3833
3878
|
// find appropriate track
|
|
3834
3879
|
if ( trackIdx >= this.animationClip.tracks.length ){ // new track ad the end
|
|
3835
3880
|
trackIdx = this.addNewTrack();
|
|
@@ -3856,6 +3901,8 @@ class ClipsTimeline extends Timeline {
|
|
|
3856
3901
|
// }
|
|
3857
3902
|
}
|
|
3858
3903
|
|
|
3904
|
+
clip.trackIdx = trackIdx;
|
|
3905
|
+
|
|
3859
3906
|
const track = this.animationClip.tracks[trackIdx];
|
|
3860
3907
|
|
|
3861
3908
|
// Find new index
|
|
@@ -4097,7 +4144,7 @@ class ClipsTimeline extends Timeline {
|
|
|
4097
4144
|
}
|
|
4098
4145
|
|
|
4099
4146
|
pasteContent( time = this.currentTime ) {
|
|
4100
|
-
this.
|
|
4147
|
+
this.deselectAllClips();
|
|
4101
4148
|
|
|
4102
4149
|
if(!this.clipboard)
|
|
4103
4150
|
return;
|
|
@@ -4155,6 +4202,11 @@ class ClipsTimeline extends Timeline {
|
|
|
4155
4202
|
const track = this.animationClip.tracks[trackIdx];
|
|
4156
4203
|
const clips = this.cloneClips(track.clips, 0, ClipsTimeline.CLONEREASON_HISTORY);
|
|
4157
4204
|
|
|
4205
|
+
// sanity check in case cloneClips misses this
|
|
4206
|
+
for( let i = 0; i < clips.length; ++i ){
|
|
4207
|
+
clips[i].trackIdx = trackIdx;
|
|
4208
|
+
}
|
|
4209
|
+
|
|
4158
4210
|
const undoStep = {
|
|
4159
4211
|
trackIdx: trackIdx, // already done by saveState
|
|
4160
4212
|
clips: clips,
|
|
@@ -4187,6 +4239,11 @@ class ClipsTimeline extends Timeline {
|
|
|
4187
4239
|
track.selected.fill(false);
|
|
4188
4240
|
track.hovered.fill(false);
|
|
4189
4241
|
|
|
4242
|
+
// sanity check. Also done in addClip
|
|
4243
|
+
for( let i = 0; i < track.clips.length; ++i ){
|
|
4244
|
+
track.clips[i].active = track.clips[i].active ?? true;
|
|
4245
|
+
}
|
|
4246
|
+
|
|
4190
4247
|
return stateToReturn;
|
|
4191
4248
|
}
|
|
4192
4249
|
|
|
@@ -4212,20 +4269,20 @@ class ClipsTimeline extends Timeline {
|
|
|
4212
4269
|
return -1;
|
|
4213
4270
|
};
|
|
4214
4271
|
|
|
4215
|
-
|
|
4272
|
+
deselectAllClips() {
|
|
4216
4273
|
|
|
4217
4274
|
for(let [trackIdx, clipIdx] of this.lastClipsSelected) {
|
|
4218
4275
|
this.animationClip.tracks[trackIdx].selected[clipIdx]= false;
|
|
4219
4276
|
}
|
|
4220
|
-
// Something has been
|
|
4221
|
-
const
|
|
4277
|
+
// Something has been deselected
|
|
4278
|
+
const deselected = this.lastClipsSelected.length > 0;
|
|
4222
4279
|
this.lastClipsSelected.length = 0;
|
|
4223
|
-
return
|
|
4280
|
+
return deselected;
|
|
4224
4281
|
}
|
|
4225
4282
|
|
|
4226
4283
|
selectAll( skipCallback = false) {
|
|
4227
4284
|
|
|
4228
|
-
this.
|
|
4285
|
+
this.deselectAllClips();
|
|
4229
4286
|
for(let trackIdx = 0; trackIdx < this.animationClip.tracks.length; trackIdx++) {
|
|
4230
4287
|
for(let clipIdx = 0; clipIdx < this.animationClip.tracks[trackIdx].clips.length; clipIdx++) {
|
|
4231
4288
|
this.animationClip.tracks[trackIdx].selected[clipIdx] = true;
|
|
@@ -4236,10 +4293,10 @@ class ClipsTimeline extends Timeline {
|
|
|
4236
4293
|
this.onSelectClip(null);
|
|
4237
4294
|
}
|
|
4238
4295
|
|
|
4239
|
-
selectClip( trackIdx, clipIndex,
|
|
4296
|
+
selectClip( trackIdx, clipIndex, deselect = true, skipCallback = false ) {
|
|
4240
4297
|
|
|
4241
|
-
if(
|
|
4242
|
-
this.
|
|
4298
|
+
if(deselect){
|
|
4299
|
+
this.deselectAllClips();
|
|
4243
4300
|
}
|
|
4244
4301
|
|
|
4245
4302
|
if(clipIndex < 0){
|
|
@@ -4270,7 +4327,7 @@ class ClipsTimeline extends Timeline {
|
|
|
4270
4327
|
return clipIndex;
|
|
4271
4328
|
}
|
|
4272
4329
|
|
|
4273
|
-
|
|
4330
|
+
deselectClip( trackIdx, clipIndex ){
|
|
4274
4331
|
|
|
4275
4332
|
if(clipIndex == -1){
|
|
4276
4333
|
return -1;
|
|
@@ -4283,7 +4340,7 @@ class ClipsTimeline extends Timeline {
|
|
|
4283
4340
|
|
|
4284
4341
|
track.selected[clipIndex] = false;
|
|
4285
4342
|
|
|
4286
|
-
//
|
|
4343
|
+
// deselect
|
|
4287
4344
|
for( let i = 0; i < this.lastClipsSelected.length; ++i){
|
|
4288
4345
|
let t = this.lastClipsSelected[i];
|
|
4289
4346
|
if ( t[0] == trackIdx && t[1] == clipIndex ){
|
|
@@ -4332,11 +4389,10 @@ class ClipsTimeline extends Timeline {
|
|
|
4332
4389
|
validateDuration(t) {
|
|
4333
4390
|
for(let i = 0; i < this.animationClip.tracks.length; i++) {
|
|
4334
4391
|
const track = this.animationClip.tracks[i];
|
|
4335
|
-
|
|
4336
|
-
|
|
4337
|
-
|
|
4338
|
-
|
|
4339
|
-
t = Math.max(t, clip.start + clip.duration);
|
|
4392
|
+
if ( track.clips.length ){
|
|
4393
|
+
const clip = track.clips[track.clips.length-1]; // assuming they are ordered ascendently
|
|
4394
|
+
t = Math.max(t, clip.start + clip.duration);
|
|
4395
|
+
}
|
|
4340
4396
|
}
|
|
4341
4397
|
return t;
|
|
4342
4398
|
}
|
|
@@ -4344,7 +4400,7 @@ class ClipsTimeline extends Timeline {
|
|
|
4344
4400
|
setDuration( t, skipCallback = false, updateHeader = true ){
|
|
4345
4401
|
const oldT = t;
|
|
4346
4402
|
const newT = this.validateDuration(t);
|
|
4347
|
-
super.setDuration(
|
|
4403
|
+
super.setDuration( newT, skipCallback, oldT != newT || updateHeader );
|
|
4348
4404
|
}
|
|
4349
4405
|
}
|
|
4350
4406
|
|