lexgui 0.4.2 → 0.5.1

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.
@@ -1,202 +1,212 @@
1
1
  import { LX } from 'lexgui';
2
2
 
3
- if(!LX) {
3
+ if( !LX )
4
+ {
4
5
  throw("lexgui.js missing!");
5
6
  }
6
7
 
7
8
  LX.components.push( 'Audio' );
8
9
 
9
10
  /**
10
- * @method addKnob
11
- * @param {String} name Widget name
12
- * @param {Number} value Knob value
13
- * @param {Number} min Min Knob value
14
- * @param {Number} max Max Knob value
15
- * @param {Function} callback Callback function on change
16
- * @param {*} options:
17
- * minLabel (String): Label to show as min value
18
- * maxLabel (String): Label to show as max value
11
+ * @class Knob
12
+ * @description Knob Widget
19
13
  */
20
14
 
21
- let Panel = LX.Panel;
22
- let Widget = LX.Widget;
15
+ class Knob extends LX.Widget {
23
16
 
24
- Panel.prototype.addKnob = function( name, value, min, max, callback, options = {} ) {
17
+ constructor( name, value, min, max, callback, options = {} ) {
25
18
 
26
- if( value.constructor == Number )
27
- {
28
- value = LX.clamp( value, min, max );
29
- value = options.precision ? LX.round( value, options.precision ) : value;
30
- }
19
+ if( value.constructor == Number )
20
+ {
21
+ value = LX.clamp( value, min, max );
22
+ value = options.precision ? LX.round( value, options.precision ) : value;
23
+ }
31
24
 
32
- let widget = this._createWidget( Widget.KNOB, name, value, options );
25
+ super( LX.Widget.KNOB, name, value, options );
33
26
 
34
- widget.onGetValue = () => {
35
- return innerKnobCircle.value;
36
- };
37
- widget.onSetValue = ( newValue, skipCallback ) => {
38
- innerSetValue( newValue );
39
- Panel._dispatch_event( innerKnobCircle, "change", skipCallback );
40
- };
27
+ this.onGetValue = () => {
28
+ return innerKnobCircle.value;
29
+ };
41
30
 
42
- let element = widget.domEl;
31
+ this.onSetValue = ( newValue, skipCallback ) => {
32
+ innerSetValue( newValue );
33
+ LX.Widget._dispatchEvent( innerKnobCircle, "change", skipCallback );
34
+ };
43
35
 
44
- const snapEnabled = ( options.snap && options.snap.constructor == Number );
45
- const ticks = [];
46
- if( snapEnabled )
47
- {
48
- const range = (max - min) / options.snap;
49
- for( let i = 0; i < ( options.snap + 1 ); ++i )
36
+ const snapEnabled = ( options.snap && options.snap.constructor == Number );
37
+ const ticks = [];
38
+ if( snapEnabled )
50
39
  {
51
- ticks.push( min + (i * range) );
40
+ const range = (max - min) / options.snap;
41
+ for( let i = 0; i < ( options.snap + 1 ); ++i )
42
+ {
43
+ ticks.push( min + (i * range) );
44
+ }
52
45
  }
53
- }
54
46
 
55
- var container = document.createElement( 'div' );
56
- container.className = "lexknob";
57
- container.addClass( options.size );
58
- container.addClass( snapEnabled ? "show-ticks" : null );
59
- container.style.width = options.inputWidth || "calc( 100% - " + LX.DEFAULT_NAME_WIDTH + ")";
60
-
61
- let knobCircle = document.createElement( 'div' );
62
- knobCircle.className = "knobcircle";
63
- if( snapEnabled )
64
- {
65
- knobCircle.style.setProperty( "--knob-snap-mark", ( 270 / options.snap ) + "deg" );
66
- }
47
+ var container = document.createElement( 'div' );
48
+ container.className = "lexknob";
49
+ container.addClass( options.size );
50
+ container.addClass( snapEnabled ? "show-ticks" : null );
51
+ container.style.width = options.inputWidth || "calc( 100% - " + LX.DEFAULT_NAME_WIDTH + ")";
67
52
 
68
- let innerKnobCircle = document.createElement( 'div' );
69
- innerKnobCircle.className = "innerknobcircle";
70
- innerKnobCircle.min = min;
71
- innerKnobCircle.max = max;
72
- knobCircle.appendChild( innerKnobCircle );
73
-
74
- let knobMarker = document.createElement( 'div' );
75
- knobMarker.className = "knobmarker";
76
- innerKnobCircle.appendChild( knobMarker );
77
- innerKnobCircle.value = innerKnobCircle.iValue = value;
78
-
79
- let mustSnap = false;
80
- let innerSetValue = function( v ) {
81
- // Convert val between (-135 and 135)
82
- const angle = LX.remapRange( v, innerKnobCircle.min, innerKnobCircle.max, -135.0, 135.0 );
83
- innerKnobCircle.style.rotate = angle + 'deg';
84
- innerKnobCircle.value = v;
85
- }
53
+ let knobCircle = document.createElement( 'div' );
54
+ knobCircle.className = "knobcircle";
55
+ if( snapEnabled )
56
+ {
57
+ knobCircle.style.setProperty( "--knob-snap-mark", ( 270 / options.snap ) + "deg" );
58
+ }
86
59
 
87
- const angle = LX.remapRange( value, min, max, -135.0, 135.0 );
88
- innerKnobCircle.style.rotate = angle + 'deg';
60
+ let innerKnobCircle = document.createElement( 'div' );
61
+ innerKnobCircle.className = "innerknobcircle";
62
+ innerKnobCircle.min = min;
63
+ innerKnobCircle.max = max;
64
+ knobCircle.appendChild( innerKnobCircle );
65
+
66
+ let knobMarker = document.createElement( 'div' );
67
+ knobMarker.className = "knobmarker";
68
+ innerKnobCircle.appendChild( knobMarker );
69
+ innerKnobCircle.value = innerKnobCircle.iValue = value;
70
+
71
+ let mustSnap = false;
72
+ let innerSetValue = function( v ) {
73
+ // Convert val between (-135 and 135)
74
+ const angle = LX.remapRange( v, innerKnobCircle.min, innerKnobCircle.max, -135.0, 135.0 );
75
+ innerKnobCircle.style.rotate = angle + 'deg';
76
+ innerKnobCircle.value = v;
77
+ }
89
78
 
90
- if( options.disabled )
91
- {
92
- container.addClass( "disabled" );
93
- }
79
+ const angle = LX.remapRange( value, min, max, -135.0, 135.0 );
80
+ innerKnobCircle.style.rotate = angle + 'deg';
94
81
 
95
- innerKnobCircle.addEventListener( "change", e => {
82
+ if( options.disabled )
83
+ {
84
+ container.addClass( "disabled" );
85
+ }
96
86
 
97
- const knob = e.target;
87
+ innerKnobCircle.addEventListener( "change", e => {
98
88
 
99
- const skipCallback = e.detail;
89
+ const knob = e.target;
100
90
 
101
- if( mustSnap )
102
- {
103
- knob.value = ticks.reduce(( prev, curr ) => Math.abs( curr - knob.value ) < Math.abs( prev - knob.value ) ? curr : prev );
104
- }
91
+ const skipCallback = e.detail;
105
92
 
106
- let val = knob.value = LX.clamp( knob.value, knob.min, knob.max );
107
- val = options.precision ? LX.round( val, options.precision ) : val;
93
+ if( mustSnap )
94
+ {
95
+ knob.value = ticks.reduce(( prev, curr ) => Math.abs( curr - knob.value ) < Math.abs( prev - knob.value ) ? curr : prev );
96
+ }
108
97
 
109
- innerSetValue( val );
98
+ let val = knob.value = LX.clamp( knob.value, knob.min, knob.max );
99
+ val = options.precision ? LX.round( val, options.precision ) : val;
110
100
 
111
- // Reset button (default value)
112
- if( !skipCallback )
113
- {
114
- let btn = element.querySelector( ".lexwidgetname .lexicon" );
115
- if( btn ) btn.style.display = val != innerKnobCircle.iValue ? "block": "none";
101
+ innerSetValue( val );
116
102
 
117
- if( !( snapEnabled && !mustSnap ) )
103
+ // Reset button (default value)
104
+ if( !skipCallback )
118
105
  {
119
- this._trigger( new LX.IEvent( name, val, e ), callback );
120
- mustSnap = false;
106
+ let btn = this.root.querySelector( ".lexwidgetname .lexicon" );
107
+ if( btn ) btn.style.display = val != innerKnobCircle.iValue ? "block": "none";
108
+
109
+ if( !( snapEnabled && !mustSnap ) )
110
+ {
111
+ this._trigger( new LX.IEvent( name, val, e ), callback );
112
+ mustSnap = false;
113
+ }
121
114
  }
122
- }
123
115
 
124
- }, { passive: false });
125
-
126
- // Add drag input
116
+ }, { passive: false });
127
117
 
128
- innerKnobCircle.addEventListener( "mousedown", inner_mousedown );
118
+ // Add drag input
129
119
 
130
- var that = this;
120
+ innerKnobCircle.addEventListener( "mousedown", inner_mousedown );
131
121
 
132
- function inner_mousedown( e ) {
122
+ var that = this;
133
123
 
134
- if( document.activeElement == innerKnobCircle || options.disabled )
135
- {
136
- return;
137
- }
124
+ function inner_mousedown( e ) {
138
125
 
139
- var doc = that.root.ownerDocument;
140
- doc.addEventListener("mousemove",inner_mousemove);
141
- doc.addEventListener("mouseup",inner_mouseup);
142
- document.body.classList.add('noevents');
126
+ if( document.activeElement == innerKnobCircle || options.disabled )
127
+ {
128
+ return;
129
+ }
143
130
 
144
- if( !document.pointerLockElement )
145
- {
146
- container.requestPointerLock();
131
+ var doc = that.root.ownerDocument;
132
+ doc.addEventListener("mousemove",inner_mousemove);
133
+ doc.addEventListener("mouseup",inner_mouseup);
134
+ document.body.classList.add('noevents');
135
+
136
+ if( !document.pointerLockElement )
137
+ {
138
+ container.requestPointerLock();
139
+ }
140
+
141
+ e.stopImmediatePropagation();
142
+ e.stopPropagation();
147
143
  }
148
144
 
149
- e.stopImmediatePropagation();
150
- e.stopPropagation();
151
- }
145
+ function inner_mousemove( e ) {
152
146
 
153
- function inner_mousemove( e ) {
147
+ let dt = -e.movementY;
154
148
 
155
- let dt = -e.movementY;
149
+ if ( dt != 0 )
150
+ {
151
+ let mult = options.step ?? 1;
152
+ if(e.shiftKey) mult *= 10;
153
+ else if(e.altKey) mult *= 0.1;
154
+ let new_value = (innerKnobCircle.value - mult * dt);
155
+ innerKnobCircle.value = new_value;
156
+ LX.Widget._dispatchEvent( innerKnobCircle, 'change' );
157
+ }
156
158
 
157
- if ( dt != 0 )
158
- {
159
- let mult = options.step ?? 1;
160
- if(e.shiftKey) mult *= 10;
161
- else if(e.altKey) mult *= 0.1;
162
- let new_value = (innerKnobCircle.value - mult * dt);
163
- innerKnobCircle.value = new_value;
164
- Panel._dispatch_event( innerKnobCircle, 'change' );
159
+ e.stopPropagation();
160
+ e.preventDefault();
165
161
  }
166
162
 
167
- e.stopPropagation();
168
- e.preventDefault();
169
- }
163
+ function inner_mouseup( e ) {
170
164
 
171
- function inner_mouseup( e ) {
165
+ var doc = that.root.ownerDocument;
166
+ doc.removeEventListener( 'mousemove', inner_mousemove );
167
+ doc.removeEventListener( 'mouseup', inner_mouseup );
168
+ document.body.classList.remove( 'noevents' );
172
169
 
173
- var doc = that.root.ownerDocument;
174
- doc.removeEventListener( 'mousemove', inner_mousemove );
175
- doc.removeEventListener( 'mouseup', inner_mouseup );
176
- document.body.classList.remove( 'noevents' );
170
+ // Snap if necessary
171
+ if( snapEnabled )
172
+ {
173
+ mustSnap = true;
174
+ LX.Widget._dispatchEvent( innerKnobCircle, 'change' );
175
+ }
177
176
 
178
- // Snap if necessary
179
- if( snapEnabled )
180
- {
181
- mustSnap = true;
182
- Panel._dispatch_event( innerKnobCircle, 'change' );
177
+ if( document.pointerLockElement )
178
+ {
179
+ document.exitPointerLock();
180
+ }
183
181
  }
184
182
 
185
- if( document.pointerLockElement )
183
+ container.appendChild( knobCircle );
184
+ this.root.appendChild( container );
185
+
186
+ // Remove branch padding and margins
187
+ if( !this.name )
186
188
  {
187
- document.exitPointerLock();
189
+ this.root.className += " noname";
190
+ container.style.width = "100%";
188
191
  }
189
192
  }
190
-
191
- container.appendChild( knobCircle );
192
- element.appendChild( container );
193
-
194
- // Remove branch padding and margins
195
- if( !widget.name )
196
- {
197
- element.className += " noname";
198
- container.style.width = "100%";
199
- }
193
+ }
194
+
195
+ LX.Knob = Knob;
196
+
197
+ /**
198
+ * @method addKnob
199
+ * @param {String} name Widget name
200
+ * @param {Number} value Knob value
201
+ * @param {Number} min Min Knob value
202
+ * @param {Number} max Max Knob value
203
+ * @param {Function} callback Callback function on change
204
+ * @param {*} options:
205
+ * minLabel (String): Label to show as min value
206
+ * maxLabel (String): Label to show as max value
207
+ */
200
208
 
201
- return widget;
209
+ LX.Panel.prototype.addKnob = function( name, value, min, max, callback, options = {} ) {
210
+ const widget = new Knob( name, value, min, max, callback, options );
211
+ return this._attachWidget( widget );
202
212
  }
@@ -302,8 +302,10 @@ class CodeEditor {
302
302
 
303
303
  this.addExplorerItem = function( item )
304
304
  {
305
- if( !this.explorer.data.children.find( (value, index) => value.id === item.id ) )
306
- this.explorer.data.children.push( item );
305
+ if( !this.explorer.innerTree.data.children.find( ( value, index ) => value.id === item.id ) )
306
+ {
307
+ this.explorer.innerTree.data.children.push( item );
308
+ }
307
309
  };
308
310
 
309
311
  explorerArea.attach( panel );
@@ -1240,7 +1242,7 @@ class CodeEditor {
1240
1242
 
1241
1243
  const ext = this.languages[ options.language ] ?. ext;
1242
1244
  this.addExplorerItem( { 'id': name, 'skipVisibility': true, 'icon': this._getFileIcon( name, ext ) } );
1243
- this.explorer.frefresh( name );
1245
+ this.explorer.innerTree.frefresh( name );
1244
1246
  }
1245
1247
  else
1246
1248
  {
@@ -1488,10 +1490,10 @@ class CodeEditor {
1488
1490
  // Update explorer icon
1489
1491
  if( this.explorer )
1490
1492
  {
1491
- const item = this.explorer.data.children.filter( (v) => v.id === this.code.tabName )[ 0 ];
1493
+ const item = this.explorer.innerTree.data.children.filter( (v) => v.id === this.code.tabName )[ 0 ];
1492
1494
  console.assert( item != undefined );
1493
1495
  item.icon = icon;
1494
- this.explorer.frefresh( this.code.tabName );
1496
+ this.explorer.innerTree.frefresh( this.code.tabName );
1495
1497
  }
1496
1498
  }
1497
1499
 
@@ -1720,7 +1722,7 @@ class CodeEditor {
1720
1722
  if( this.explorer && !isNewTabButton )
1721
1723
  {
1722
1724
  this.addExplorerItem( { 'id': name, 'skipVisibility': true, 'icon': tabIcon } );
1723
- this.explorer.frefresh( name );
1725
+ this.explorer.innerTree.frefresh( name );
1724
1726
  }
1725
1727
 
1726
1728
  this.tabs.add( name, code, {
@@ -95,11 +95,12 @@ class GraphEditor {
95
95
  this._sidebar = area.addSidebar( m => {
96
96
 
97
97
  }, {
98
- headerIcon: "More",
98
+ displaySelected: true,
99
+ headerIcon: "more",
99
100
  headerTitle: "Create",
100
101
  headerSubtitle: "Press to rename",
101
102
  onHeaderPressed: () => this._showRenameGraphDialog(),
102
- footerIcon: "Plus",
103
+ footerIcon: "plus",
103
104
  footerTitle: "Create",
104
105
  footerSubtitle: "Graph or Function",
105
106
  onFooterPressed: (e) => this._onSidebarCreate( e )
@@ -1204,7 +1205,7 @@ class GraphEditor {
1204
1205
  panel.addVector4( p.name, p.value, (v) => { p.value = v } );
1205
1206
  break;
1206
1207
  case 'select':
1207
- panel.addDropdown( p.name, p.options, p.value, (v) => { p.value = v } );
1208
+ panel.addSelect( p.name, p.options, p.value, (v) => { p.value = v } );
1208
1209
  break;
1209
1210
  case 'array':
1210
1211
  panel.addArray( p.name, p.value, (v) => {
@@ -169,7 +169,6 @@ class Timeline {
169
169
  }
170
170
 
171
171
  let header = this.header;
172
- LX.DEFAULT_NAME_WIDTH = "50%";
173
172
  header.sameLine();
174
173
 
175
174
  if( this.name )
@@ -177,32 +176,54 @@ class Timeline {
177
176
  header.addTitle(this.name );
178
177
  }
179
178
 
180
- header.addButton('', '<i class="fa-solid fa-'+ (this.playing ? 'pause' : 'play') +'"></i>', (value, event) => {
179
+ const buttonContainer = LX.makeContainer(["auto", "100%"], "", { display: "flex" });
180
+
181
+ header.queue( buttonContainer );
182
+
183
+ header.addButton("playBtn", '<i class="fa-solid fa-'+ (this.playing ? 'pause' : 'play') +'"></i>', (value, event) => {
181
184
  this.changeState();
182
- }, { width: "40px", buttonClass: "accept", title: "Play" });
185
+ }, { buttonClass: "accept", title: "Play", hideName: true });
183
186
 
184
- header.addButton('', '<i class="fa-solid fa-rotate"></i>', ( value, event ) => {
187
+ header.addButton("toggleLoopBtn", '<i class="fa-solid fa-rotate"></i>', ( value, event ) => {
185
188
  this.loop = !this.loop;
186
189
  if( this.onChangePlayMode )
187
190
  {
188
191
  this.onChangePlayMode( this.loop );
189
192
  }
190
- }, { width: "40px", selectable: true, selected: this.loop, title: 'Loop' });
193
+ }, { selectable: true, selected: this.loop, title: 'Loop', hideName: true });
191
194
 
192
195
  if( this.onBeforeCreateTopBar )
193
196
  {
194
197
  this.onBeforeCreateTopBar( header );
195
198
  }
196
199
 
200
+ header.clearQueue( buttonContainer );
201
+
202
+ header.addContent( "header-buttons", buttonContainer );
203
+
197
204
  header.addNumber("Current Time", this.currentTime, (value, event) => {
198
- this.setTime(value)}, {signal: "@on_set_time_" + this.name, step: 0.01, min: 0, precision: 3, skipSlider: true});
205
+ this.setTime(value)
206
+ }, {
207
+ units: "s",
208
+ signal: "@on_set_time_" + this.name,
209
+ step: 0.01, min: 0, precision: 3,
210
+ skipSlider: true
211
+ });
199
212
 
200
213
  header.addNumber("Duration", + this.duration.toFixed(3), (value, event) => {
201
- this.setDuration(value, false)}, {step: 0.01, min: 0, signal: "@on_set_duration_" + this.name
214
+ this.setDuration(value, false)
215
+ }, {
216
+ units: "s",
217
+ step: 0.01, min: 0,
218
+ signal: "@on_set_duration_" + this.name
202
219
  });
203
220
 
204
221
  header.addNumber("Speed", + this.speed.toFixed(3), (value, event) => {
205
- this.setSpeed(value)}, {step: 0.01, signal: "@on_set_speed_" + this.name});
222
+ this.setSpeed(value)
223
+ }, {
224
+ step: 0.01,
225
+ signal: "@on_set_speed_" + this.name
226
+ });
206
227
 
207
228
  if( this.onAfterCreateTopBar )
208
229
  {
@@ -211,12 +232,12 @@ class Timeline {
211
232
 
212
233
  if( this.onShowOptimizeMenu )
213
234
  {
214
- header.addButton("", '<i class="fa-solid fa-filter"></i>', (value, event) => {this.onShowOptimizeMenu(event)}, { width: "40px", title: "Optimize" });
235
+ header.addButton(null, '<i class="fa-solid fa-filter"></i>', (value, event) => {this.onShowOptimizeMenu(event)}, { title: "Optimize" });
215
236
  }
216
237
 
217
238
  if( this.onShowConfiguration )
218
239
  {
219
- header.addButton("", '<i class="fa-solid fa-gear"></i>', (value, event) => {
240
+ header.addButton(null, '<i class="fa-solid fa-gear"></i>', (value, event) => {
220
241
  if(this.configurationDialog){
221
242
  this.configurationDialog.close();
222
243
  this.configurationDialog = null;
@@ -231,11 +252,10 @@ class Timeline {
231
252
  root.remove();
232
253
  }
233
254
  })
234
- }, { width: "40px" })
255
+ }, { title: "Settings" })
235
256
  }
236
257
 
237
258
  header.endLine();
238
- LX.DEFAULT_NAME_WIDTH = "30%";
239
259
  }
240
260
 
241
261
  /**
@@ -258,13 +278,14 @@ class Timeline {
258
278
  let panel = this.leftPanel;
259
279
  panel.sameLine( 2 );
260
280
 
261
- let title = panel.addTitle( "Tracks" );
281
+ let titleWidget = panel.addTitle( "Tracks" );
282
+ let title = titleWidget.root;
262
283
 
263
284
  if( !this.disableNewTracks )
264
285
  {
265
- panel.addButton('', '<i class = "fa-solid fa-plus"></i>', (value, event) => {
286
+ panel.addButton("addTrackBtn", '<i class = "fa-solid fa-plus"></i>', (value, event) => {
266
287
  this.addNewTrack();
267
- }, {width: "40px", height: "40px"});
288
+ }, { hideName: true, title: "Add Track" });
268
289
  }
269
290
 
270
291
  panel.endLine();
@@ -2752,12 +2773,14 @@ class ClipsTimeline extends Timeline {
2752
2773
  let panel = this.leftPanel;
2753
2774
 
2754
2775
  panel.sameLine(2);
2755
- let title = panel.addTitle("Tracks");
2776
+
2777
+ let titleWidget = panel.addTitle("Tracks");
2778
+ let title = titleWidget.root;
2756
2779
  if(!this.disableNewTracks)
2757
2780
  {
2758
- panel.addButton('', '<i class = "fa-solid fa-plus"></i>', (value, event) => {
2781
+ panel.addButton("addTrackBtn", '<i class = "fa-solid fa-plus"></i>', (value, event) => {
2759
2782
  this.addNewTrack();
2760
- }, {width: "40px", height: "40px"});
2783
+ }, { hideName: true, title: "Add Track" });
2761
2784
  }
2762
2785
  panel.endLine();
2763
2786
  const styles = window.getComputedStyle(title);