lexgui 0.7.8 → 0.7.10

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/changelog.md CHANGED
@@ -2,7 +2,49 @@
2
2
 
3
3
  ## dev
4
4
 
5
- ## 0.7.8 (master)
5
+ ## 0.7.10 (master)
6
+
7
+ Removed Fit-Tabs thumb CSS transition on `Tabs.add`.
8
+ Added Popover documentation.
9
+ Fixed `LX.codeSnippet` linesAdded/Removed options.
10
+ Fixed `Area.extend()` and `Area.reduce()` transitions.
11
+
12
+ AssetView:
13
+ - Added support for video elements.
14
+ - Fixed support for images using url with params.
15
+ - Added more supported image extensions.
16
+ - Updated documentation.
17
+
18
+ CodeEditor:
19
+ - Added support to `options.callback` to call when the editor is completely loaded.
20
+ - Docs updated.
21
+
22
+ Timeline:
23
+ - Added `Timeline.setKeyframeSize` and `Timeline.setTrackHeight`.
24
+ - Curve keyframes are visually clamped to the tracks' boundaries.
25
+ - Fixed `Add Keyframe` option in context menu.
26
+
27
+ VideoEditor:
28
+ - Minor functions refactor.
29
+ - Speed and loop buttons added to video controls.
30
+ - Fixed resize controls area bug.
31
+
32
+ ## 0.7.9
33
+
34
+ Allow wheel/middle click in menubar buttons.
35
+ Pass RadioGroup name as argument to radio option callback.
36
+
37
+ CodeEditor:
38
+ - Fixed remove old selections on Select All.
39
+ - Fixed Find next occurrence cursors (ctrl+D).
40
+ - Added `CodeEditor.setCustomSuggestions(Array)`.
41
+
42
+ VideoEditor:
43
+ - Time marker ball improved to be showed above trim markers.
44
+ - Force to load all chunks of the video.
45
+ - Loop video manually done to fix sync.
46
+
47
+ ## 0.7.8
6
48
 
7
49
  Renamed AssetView "List" view to "Compact". Added better "List" view option.
8
50
  Fixed undesired scroll in AssetView.
@@ -26,7 +26,7 @@
26
26
  let area = await LX.init();
27
27
 
28
28
  // split main area
29
- var [leftArea, rightArea] = area.split({ sizes: ["75%", "25%"] });
29
+ var [ leftArea, rightArea ] = area.split({ sizes: ["75%", "25%"], minimizable: true });
30
30
 
31
31
  // Get new content area to fill it
32
32
  const leftTabs = leftArea.addTabs();
@@ -56,7 +56,33 @@
56
56
  {
57
57
  id: "dog.png",
58
58
  type: "image",
59
- path: "https://pngfre.com/wp-content/uploads/1653714420512-1-904x1024.png"
59
+ src: "https://pngfre.com/wp-content/uploads/1653714420512-1-904x1024.png"
60
+ },
61
+ {
62
+ id: "greenland_grid_velo.bmp",
63
+ type: "image",
64
+ src: "https://people.math.sc.edu/Burkardt/data/bmp/greenland_grid_velo.bmp"
65
+ },
66
+ {
67
+ id: "Fox Monochrome.avif",
68
+ type: "image",
69
+ src: "https://raw.githubusercontent.com/link-u/avif-sample-images/refs/heads/master/fox.profile0.10bpc.yuv420.monochrome.avif"
70
+ },
71
+ {
72
+ id: "Avatar",
73
+ type: "Avatar",
74
+ preview: "https://models.readyplayer.me/66e30a18eca8fb70dcadde68.png?background=68,68,245"
75
+ },
76
+ {
77
+ id: "video-test",
78
+ type: "video",
79
+ preview: "https://godotengine.org/assets/press/logo_vertical_color_dark.png",
80
+ src: "https://catsl.eelvex.net/static/vid/teacher-video-Ψ.mp4"
81
+ },
82
+ {
83
+ id: "nyan-pyportal.gif",
84
+ type: "image",
85
+ src: "../data/nyan-pyportal.gif"
60
86
  },
61
87
  {
62
88
  id: "sigml_test.sigml",
@@ -48,15 +48,17 @@
48
48
  const types = { KEYFRAMES: 0, CLIPS: 1, CURVES: 2};
49
49
  let position = [250, 350];
50
50
  let trackName = "";
51
+ let kfTimeline = null;
51
52
 
52
53
  let panel = new LX.Panel();
53
54
  panel = rightArea.addPanel(panel);
54
- fillPanel( panel );
55
-
55
+
56
56
  let activeTimeline = null
57
57
  createKeyframeTimeline( bottomTabs );
58
58
  createClipsTimeline( bottomTabs );
59
59
  createCurvesTimeline( bottomTabs );
60
+
61
+ fillPanel( panel );
60
62
 
61
63
  LX.doAsync( activeTimeline.resize.bind( activeTimeline ) );
62
64
 
@@ -144,8 +146,17 @@
144
146
  track.edited[keyframe] = true;
145
147
  }
146
148
  }, { min: 0, max: 1024 });
147
- panel.branch_open = true;
148
149
  panel.merge();
150
+
151
+ panel.addRange("Keyframe Size", kfTimeline.keyframeSize / kfTimeline.trackHeight, (v,e)=>{
152
+ kfTimeline.keyframeSize = v * kfTimeline.trackHeight;
153
+ }, { step: 0.001, min: 0, max: 1 });
154
+
155
+ panel.addNumber("Track Height", kfTimeline.trackHeight, (v,e)=>{
156
+ let ratio = kfTimeline.keyframeSize / kfTimeline.trackHeight;
157
+ kfTimeline.setTrackHeight(v);
158
+ kfTimeline.setKeyframeSize( kfTimeline.trackHeight * ratio, kfTimeline.trackHeight * ratio + 6 );
159
+ }, { step: 1, min: parseFloat(getComputedStyle(document.documentElement).fontSize) * 0.25 });
149
160
  }
150
161
 
151
162
 
@@ -206,7 +217,7 @@
206
217
  keyframesPanel.onresize = () => {
207
218
  kfTimeline.resize();
208
219
  }
209
- let kfTimeline = new LX.KeyFramesTimeline('Keyframes Timeline', {
220
+ kfTimeline = new LX.KeyFramesTimeline('Keyframes Timeline', {
210
221
  disableNewTracks: true,
211
222
  onCreateBeforeTopBar: (panel) => {
212
223
  panel.addSelect("Animation", ["Anim 1", "Anim 2", "Anim 3"], "Anim 1", ()=> {})
@@ -224,25 +235,24 @@
224
235
  kfTimeline.show();
225
236
 
226
237
 
227
- kfTimeline.onSelectKeyFrame = (data, currentSelection) => {
228
- if(data.multipleSelection) {
238
+ kfTimeline.onSelectKeyFrame = (currentSelection) => {
239
+ if(kfTimeline.lastKeyFramesSelected.length > 1) {
229
240
  rightArea.hide();
230
241
  return;
231
242
  }
232
243
  rightArea.show();
233
- trackName = data.track.id ;
234
- if( data.track.groupId != "Font" || data.track.id != "position") {
244
+ const track = kfTimeline.animationClip.tracks[currentSelection[0]];
245
+ trackName = track.id ;
246
+ if( track.groupId != "Font" || track.id != "position") {
235
247
  return
236
248
  }
237
- const id = data.track.trackIdx;
238
- let values = kfTimeline.animationClip.tracks[id].values;
239
- const dim = kfTimeline.animationClip.tracks[id].dim;
249
+ const idx = track.trackIdx;
250
+ let values = track.values;
251
+ const dim = track.dim;
240
252
 
241
- //currentSelection == [track.name, track.idx, frameIdx, track.clipIdx, track.times[frameIdx]]
242
253
  const keyFrameIndex = currentSelection[1];
243
254
  position = values.slice(keyFrameIndex * dim, keyFrameIndex * dim + dim);
244
255
  fillPanel(panel);
245
- //kfTimeline.animationClip.tracks[currentSelection[0][0]];
246
256
  }
247
257
 
248
258
  kfTimeline.onSetTime = ( time ) => {
@@ -21,6 +21,155 @@
21
21
 
22
22
  import { LX } from 'lexgui';
23
23
  import { VideoEditor } from 'lexgui/extensions/videoeditor.js';
24
+
25
+ class Window {
26
+ constructor( timeline, options = {} ) {
27
+ this.timeline = timeline;
28
+ this.timeline.padding = 0;
29
+
30
+ this.start = options.start != undefined ? options.start : 0.0; // sec
31
+ this.end = options.end || 3.0; // sec
32
+ this.center = options.center != undefined ? options.center : this.start
33
+
34
+ this.canvas = this.timeline.canvas;
35
+ this.windowHeight = options.windowHeight || this.canvas.height - 15;
36
+ this.handleWidth = options.handleWidth || 6;
37
+
38
+ this.allowDragging = options.dragging ?? false;
39
+ this.dragging = false;
40
+ this.dragOffset = 0;
41
+ this.resizingLeft = false;
42
+ this.resizingRight = false;
43
+ }
44
+
45
+ draw() {
46
+ const ctx = this.canvas.getContext('2d');
47
+ let startX = Math.max( this.timeline.startX, this.timeline.timeToX(this.start) );
48
+ let endX = Math.min( this.timeline.endX, this.timeline.timeToX(this.end) );
49
+ const width = endX - startX;
50
+
51
+ // Window background
52
+ ctx.fillStyle = "rgba(200, 200, 255, 0.15)";
53
+ ctx.roundRect(startX , this.canvas.height / 2 - this.windowHeight / 2, width, this.windowHeight, 5);
54
+ ctx.fill();
55
+ // Border
56
+ ctx.strokeStyle = "rgba(200, 200, 255, 0.5)";
57
+ ctx.lineWidth = 1;
58
+ ctx.beginPath();
59
+ ctx.roundRect(startX, this.canvas.height / 2 - this.windowHeight / 2, width, this.windowHeight, 5);
60
+ ctx.stroke();
61
+
62
+ // Handlers
63
+ const offsetW = 2;
64
+ const offsetH = 8;
65
+ if( startX > this.timeline.startX ) {
66
+ ctx.fillStyle = "whitesmoke"//"#579aff";
67
+ ctx.fillRect(startX, this.canvas.height / 2 - this.windowHeight / 2, this.handleWidth, this.windowHeight);
68
+ ctx.fillStyle = "#579aff";
69
+ ctx.fillRect(startX + this.handleWidth/2 - offsetW/2, this.canvas.height / 2 - this.windowHeight / 2 + offsetH / 2 , offsetW, this.windowHeight - offsetH);
70
+ }
71
+ if( endX < this.timeline.endX ) {
72
+ ctx.fillStyle = "whitesmoke"//"#579aff";
73
+ ctx.fillRect(endX - this.handleWidth, this.canvas.height / 2 - this.windowHeight / 2, this.handleWidth, this.windowHeight);
74
+ ctx.fillStyle = "#579aff";
75
+ ctx.fillRect(endX - this.handleWidth/2 - offsetW/2, this.canvas.height / 2 - this.windowHeight / 2 + offsetH / 2, offsetW, this.windowHeight - offsetH);
76
+ }
77
+ }
78
+
79
+ onMouse( e ) {
80
+ switch(e.type) {
81
+ case "mousedown":
82
+ this.onMouseDown( e );
83
+ break;
84
+ case "mousemove":
85
+ this.onMouseMove( e );
86
+ break;
87
+ case "mouseup":
88
+ this.onMouseUp( e );
89
+ break;
90
+ }
91
+ }
92
+
93
+ onMouseDown( e ) {
94
+ const x = e.offsetX;
95
+ const startX = this.timeline.timeToX(this.start);
96
+ const endX = this.timeline.timeToX(this.end);
97
+
98
+ if( x >= startX && x <= startX + this.handleWidth ) {
99
+ this.resizingLeft = true;
100
+ e.cancelBubble = true;
101
+ }
102
+ else if( x >= endX - this.handleWidth && x <= endX ) {
103
+ this.resizingRight = true;
104
+ e.cancelBubble = true;
105
+ }
106
+ else if( this.allowDragging && x >= startX && x <= endX ) {
107
+ this.dragging = true;
108
+ this.dragOffset = x - startX;
109
+ e.cancelBubble = true;
110
+ }
111
+ }
112
+
113
+ onMouseMove( e ) {
114
+ const x = e.offsetX;
115
+ let startX = this.timeline.timeToX(this.start);
116
+ let endX = this.timeline.timeToX(this.end);
117
+ const centerX = this.timeline.timeToX(this.center);
118
+ if( this.resizingLeft ) {
119
+ startX = Math.min( centerX, Math.max( this.timeline.startX, x ) );//Math.max(startX - 0.1, (x - this.timeline.padding) / (this.canvas.width - 2 * this.timeline.padding) * this.timeline.endX);
120
+ this.start = this.timeline.xToTime( startX );
121
+ }
122
+ else if( this.resizingRight ) {
123
+ endX = Math.max( centerX, Math.min( this.timeline.endX, x ) ); //Math.min(endX + 0.1, (x - this.timeline.padding) / (this.canvas.width - 2 * this.timeline.padding) * this.timeline.endX);
124
+ this.end = this.timeline.xToTime( endX );
125
+ }
126
+ else if( this.dragging ) {
127
+ const time = this.timeline.xToTime( x - this.dragOffset );
128
+ this.moveWindow( time )
129
+ }
130
+ else {
131
+ const x = e.offsetX;
132
+ const startX = this.timeline.timeToX(this.start);
133
+ const endX = this.timeline.timeToX(this.end);
134
+
135
+ if( x >= startX && x <= startX + this.handleWidth ) {
136
+ this.canvas.style.cursor = "col-resize";
137
+ e.cancelBubble = true;
138
+ }
139
+ else if( x >= endX - this.handleWidth && x <= endX ) {
140
+ this.canvas.style.cursor = "col-resize";
141
+ e.cancelBubble = true;
142
+ }
143
+ return;
144
+ }
145
+ e.cancelBubble = true;
146
+ this.timeline._draw();
147
+ }
148
+
149
+ onMouseUp( e ) {
150
+ this.dragging = false;
151
+ this.resizingLeft = false;
152
+ this.resizingRight = false;
153
+ }
154
+
155
+ moveWindow( time ) {
156
+
157
+ const leftOffset = this.start - this.center;
158
+ const rightOffset = this.end - this.center;
159
+
160
+ // const startX = this.timeline.timeToX( time + leftOffset );
161
+ // const endX = this.timeline.timeToX( rightOffset );
162
+
163
+ // const windowLength = this.end - this.start;
164
+
165
+ // newStart = Math.max(0, Math.min(this.timeline.endX - windowLength, startX));
166
+ this.start = time + leftOffset;
167
+ this.end = time + rightOffset;
168
+ this.center = time;
169
+ }
170
+
171
+ }
172
+
24
173
  // init library and get main area
25
174
  let area = await LX.init();
26
175
 
@@ -33,9 +182,9 @@
33
182
  video.src = "../data/video.mp4";
34
183
  videoArea.attach(video);
35
184
 
36
- const videoEditor = new LX.VideoEditor(leftArea, { videoArea, video, crop: true })
37
- videoEditor._loadVideo();
38
-
185
+ const videoEditor = new LX.VideoEditor(leftArea, { videoArea, video, crop: true, loop: true })
186
+ videoEditor.loadVideo();
187
+
39
188
  const canvas = document.createElement('canvas');
40
189
  canvas.width = video.clientWidth;
41
190
  canvas.height = video.clientHeight;
@@ -30,7 +30,7 @@
30
30
  // Split main area
31
31
  let [leftArea, rightArea] = area.split({ sizes: ["75%", "25%"], minimizable: true });
32
32
  let [topArea, bottomArea] = leftArea.split({ sizes: ["80%", null], minimizable: false, resize: false, type: "vertical" });
33
- let [controlsArea, buttonsArea] = bottomArea.split({ sizes: ["50%", null], minimizable: false, resize: false, type: "vertical" });
33
+ let [controlsArea, buttonsArea] = bottomArea.split({ sizes: ["50%", null], minimizable: false, type: "vertical" });
34
34
  area.extend();
35
35
 
36
36
  /* Create video area with a menubar */
@@ -41,7 +41,8 @@
41
41
  video.src = "../data/video.mp4";
42
42
  videoArea.attach(video);
43
43
  const videoEditor = new LX.VideoEditor(topArea, { videoArea, video, controlsArea })
44
- videoEditor._loadVideo();
44
+ videoEditor.loadVideo();
45
+
45
46
  /* Add canvas above video */
46
47
  const canvas = document.createElement('canvas');
47
48
  canvas.width = video.clientWidth;
@@ -72,7 +73,7 @@
72
73
  icon: "Info",
73
74
  name: "Properties",
74
75
  callback: (v, e) => {
75
- if (area.split_extended) {
76
+ if (area.splitExtended) {
76
77
  area.reduce();
77
78
  }
78
79
  else {
@@ -92,8 +93,7 @@
92
93
  /* Create right panel */
93
94
  let panel = new LX.Panel({ id: "Properties" });
94
95
  panel = rightArea.addPanel({ id: "Properties" });
95
- createBlendShapesInspector({ "Name 1": 0, "Name 2": 0, "Name 3": 0.5, "Name 4": 0, "Name 5": 1, },
96
- { inspector: panel });
96
+ createBlendShapesInspector({ "Name 1": 0, "Name 2": 0, "Name 3": 0.5, "Name 4": 0, "Name 5": 1, }, { inspector: panel });
97
97
 
98
98
  /* Functions */
99
99
  function createBlendShapesInspector(bsNames, options = {}) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lexgui",
3
- "version": "0.7.8",
3
+ "version": "0.7.10",
4
4
  "description": "JS library to create web graphical user interfaces",
5
5
  "type": "module",
6
6
  "main": "./build/lexgui.js",