lexgui 0.1.36 → 0.1.39

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/build/lexgui.js CHANGED
@@ -12,7 +12,7 @@ console.warn( 'Script "build/lexgui.js" is depracated and will be removed soon.
12
12
  */
13
13
 
14
14
  var LX = global.LX = {
15
- version: "0.1.36",
15
+ version: "0.1.39",
16
16
  ready: false,
17
17
  components: [], // specific pre-build components
18
18
  signals: {} // events and triggers
@@ -29,7 +29,12 @@ console.warn( 'Script "build/lexgui.js" is depracated and will be removed soon.
29
29
  LX.CURVE_MOVEOUT_DELETE = 1;
30
30
 
31
31
  function clamp( num, min, max ) { return Math.min( Math.max( num, min ), max ); }
32
- function round( num, n ) { return +num.toFixed( n ); }
32
+ function round( number, precision ) { return +(( number ).toFixed( precision ?? 2 ).replace( /([0-9]+(\.[0-9]+[1-9])?)(\.?0+$)/, '$1' )); }
33
+ function remapRange( oldValue, oldMin, oldMax, newMin, newMax ) { return ((( oldValue - oldMin ) * ( newMax - newMin )) / ( oldMax - oldMin )) + newMin; }
34
+
35
+ LX.clamp = clamp;
36
+ LX.round = round;
37
+ LX.remapRange = remapRange;
33
38
 
34
39
  function getSupportedDOMName( string )
35
40
  {
@@ -106,6 +111,18 @@ console.warn( 'Script "build/lexgui.js" is depracated and will be removed soon.
106
111
 
107
112
  LX.rgbToHex = rgbToHex;
108
113
 
114
+ function measureRealWidth( value, paddingPlusMargin = 8 ) {
115
+ var i = document.createElement( "span" );
116
+ i.className = "lexinputmeasure";
117
+ i.innerHTML = value;
118
+ document.body.appendChild( i );
119
+ var rect = i.getBoundingClientRect();
120
+ LX.UTILS.deleteElement( i );
121
+ return rect.width + paddingPlusMargin;
122
+ }
123
+
124
+ LX.measureRealWidth = measureRealWidth;
125
+
109
126
  function simple_guidGenerator() {
110
127
  var S4 = function() {
111
128
  return (((1+Math.random())*0x10000)|0).toString(16).substring(1);
@@ -113,6 +130,8 @@ console.warn( 'Script "build/lexgui.js" is depracated and will be removed soon.
113
130
  return (S4()+"-"+S4()+"-"+S4());
114
131
  }
115
132
 
133
+ LX.guidGenerator = simple_guidGenerator;
134
+
116
135
  // Timer that works everywhere (from litegraph.js)
117
136
  if (typeof performance != "undefined") {
118
137
  LX.getTime = performance.now.bind(performance);
@@ -165,46 +184,79 @@ console.warn( 'Script "build/lexgui.js" is depracated and will be removed soon.
165
184
  len () { return Math.sqrt( this.len2() ); }
166
185
  nrm ( v0 = new vec2() ) { v0.set( this.x, this.y ); return v0.mul( 1.0 / this.len(), v0 ); }
167
186
  dst ( v ) { return v.sub( this ).len(); }
187
+ clp ( min, max, v0 = new vec2() ) { v0.set( clamp( this.x, min, max ), clamp( this.y, min, max ) ); return v0; }
168
188
  };
169
189
 
170
190
  LX.vec2 = vec2;
171
191
 
172
192
  // Other utils
173
193
 
194
+ /**
195
+ * @method makeDraggable
196
+ * @param {Element} domEl
197
+ * @param {Object} options
198
+ * autoAdjust (Bool): Sets in a correct position at the beggining
199
+ * dragMargin (Number): Margin of drag container
200
+ * onMove (Function): Called each move event
201
+ * onDragStart (Function): Called when drag event starts
202
+ */
174
203
  function makeDraggable( domEl, options = { } ) {
175
204
 
176
- let offsetX;
177
- let offsetY;
205
+ let offsetX = 0;
206
+ let offsetY = 0;
178
207
  let currentTarget = null;
179
208
  let targetClass = options.targetClass;
180
-
209
+ let dragMargin = options.dragMargin ?? 3;
210
+
211
+ let _computePosition = ( e, top, left ) => {
212
+ const nullRect = { x: 0, y: 0, width: 0, height: 0 };
213
+ const parentRect = domEl.parentElement ? domEl.parentElement.getBoundingClientRect() : nullRect;
214
+ const isFixed = ( domEl.style.position == "fixed" );
215
+ const fixedOffset = isFixed ? new LX.vec2( parentRect.x, parentRect.y ) : new LX.vec2();
216
+ left = left ?? e.clientX - offsetX - parentRect.x;
217
+ top = top ?? e.clientY - offsetY - parentRect.y;
218
+ domEl.style.left = clamp( left, dragMargin + fixedOffset.x, fixedOffset.x + parentRect.width - domEl.offsetWidth - dragMargin ) + 'px';
219
+ domEl.style.top = clamp( top, dragMargin + fixedOffset.y, fixedOffset.y + parentRect.height - domEl.offsetHeight - dragMargin ) + 'px';
220
+ };
221
+
222
+ // Initial adjustment
223
+ if( options.autoAdjust )
224
+ {
225
+ _computePosition( null, parseInt( domEl.style.left ), parseInt( domEl.style.top ) )
226
+ }
227
+
181
228
  let id = LX.UTILS.uidGenerator();
182
229
  domEl[ 'draggable-id' ] = id;
183
-
230
+
184
231
  const defaultMoveFunc = e => {
185
- if( !currentTarget ) return;
186
- let left = e.clientX - offsetX;
187
- let top = e.clientY - offsetY;
188
- if( left > 3 && ( left + domEl.offsetWidth + 6 ) <= window.innerWidth )
189
- domEl.style.left = left + 'px';
190
- if( top > 3 && ( top + domEl.offsetHeight + 6 ) <= window.innerHeight )
191
- domEl.style.top = top + 'px';
232
+ if( !currentTarget )
233
+ {
234
+ return;
235
+ }
236
+
237
+ _computePosition( e );
192
238
  };
193
-
239
+
194
240
  const customMoveFunc = e => {
195
- if( !currentTarget ) return;
241
+ if( !currentTarget )
242
+ {
243
+ return;
244
+ }
245
+
196
246
  if( options.onMove )
247
+ {
197
248
  options.onMove( currentTarget );
249
+ }
198
250
  };
199
-
251
+
200
252
  let onMove = options.onMove ? customMoveFunc : defaultMoveFunc;
201
253
  let onDragStart = options.onDragStart;
202
-
254
+
203
255
  domEl.setAttribute( 'draggable', true );
204
256
  domEl.addEventListener( "mousedown", function( e ) {
205
- currentTarget = (e.target.classList.contains(targetClass) || !targetClass) ? e.target : null;
257
+ currentTarget = ( e.target.classList.contains( targetClass ) || !targetClass ) ? e.target : null;
206
258
  } );
207
-
259
+
208
260
  domEl.addEventListener( "dragstart", function( e ) {
209
261
  e.preventDefault();
210
262
  e.stopPropagation();
@@ -216,15 +268,21 @@ console.warn( 'Script "build/lexgui.js" is depracated and will be removed soon.
216
268
  e.dataTransfer.setDragImage( img, 0, 0 );
217
269
  e.dataTransfer.effectAllowed = "move";
218
270
  const rect = e.target.getBoundingClientRect();
219
- offsetX = e.clientX - rect.x;
220
- offsetY = e.clientY - rect.y;
271
+ const parentRect = currentTarget.parentElement.getBoundingClientRect();
272
+ const isFixed = ( currentTarget.style.position == "fixed" );
273
+ const fixedOffset = isFixed ? new LX.vec2( parentRect.x, parentRect.y ) : new LX.vec2();
274
+ offsetX = e.clientX - rect.x - fixedOffset.x;
275
+ offsetY = e.clientY - rect.y - fixedOffset.y;
221
276
  document.addEventListener( "mousemove", onMove );
222
277
  if( onDragStart )
278
+ {
223
279
  onDragStart( currentTarget, e );
280
+ }
224
281
  }, false );
225
282
 
226
283
  document.addEventListener( 'mouseup', () => {
227
- if( currentTarget ) {
284
+ if( currentTarget )
285
+ {
228
286
  currentTarget = null;
229
287
  document.removeEventListener( "mousemove", onMove );
230
288
  }
@@ -304,11 +362,18 @@ console.warn( 'Script "build/lexgui.js" is depracated and will be removed soon.
304
362
  else
305
363
  {
306
364
  for( let c of LX.components )
307
- if( LX[c].prototype.onKeyPressed )
365
+ {
366
+ if( !LX[c] || !LX[c].prototype.onKeyPressed )
367
+ {
368
+ continue;
369
+ }
370
+
371
+ const instances = LX.CodeEditor.getInstances();
372
+ for( let i of instances )
308
373
  {
309
- const instances = LX.CodeEditor.getInstances();
310
- for( let i of instances ) i.onKeyPressed( e );
374
+ i.onKeyPressed( e );
311
375
  }
376
+ }
312
377
  }
313
378
  });
314
379
 
@@ -634,6 +699,8 @@ console.warn( 'Script "build/lexgui.js" is depracated and will be removed soon.
634
699
  }
635
700
  };
636
701
 
702
+ LX.IEvent = IEvent;
703
+
637
704
  class TreeEvent {
638
705
 
639
706
  static NONE = 0;
@@ -654,7 +721,8 @@ console.warn( 'Script "build/lexgui.js" is depracated and will be removed soon.
654
721
  }
655
722
 
656
723
  string() {
657
- switch(this.type) {
724
+ switch( this.type )
725
+ {
658
726
  case TreeEvent.NONE: return "tree_event_none";
659
727
  case TreeEvent.NODE_SELECTED: return "tree_event_selected";
660
728
  case TreeEvent.NODE_DELETED: return "tree_event_deleted";
@@ -808,7 +876,9 @@ console.warn( 'Script "build/lexgui.js" is depracated and will be removed soon.
808
876
 
809
877
  const draggable = options.draggable ?? true;
810
878
  if( draggable )
811
- makeDraggable( root );
879
+ {
880
+ makeDraggable( root, options );
881
+ }
812
882
 
813
883
  if( options.resizeable ) {
814
884
  root.classList.add("resizeable");
@@ -1170,23 +1240,33 @@ console.warn( 'Script "build/lexgui.js" is depracated and will be removed soon.
1170
1240
  * @method resize
1171
1241
  * Resize element
1172
1242
  */
1173
- setSize(size) {
1243
+ setSize( size ) {
1174
1244
 
1175
- let [width, height] = size;
1176
-
1177
- if(width != undefined && width.constructor == Number)
1245
+ let [ width, height ] = size;
1246
+
1247
+ if( width != undefined && width.constructor == Number )
1248
+ {
1178
1249
  width += "px";
1179
- if(height != undefined && height.constructor == Number)
1250
+ }
1251
+
1252
+ if( height != undefined && height.constructor == Number )
1253
+ {
1180
1254
  height += "px";
1181
-
1182
- if(width)
1255
+ }
1256
+
1257
+ if( width )
1258
+ {
1183
1259
  this.root.style.width = width;
1184
- if(height)
1260
+ }
1261
+
1262
+ if( height )
1263
+ {
1185
1264
  this.root.style.height = height;
1265
+ }
1186
1266
 
1187
- this.size = [this.root.clientWidth, this.root.clientHeight];
1267
+ this.size = [ this.root.clientWidth, this.root.clientHeight ];
1188
1268
 
1189
- this.propagateEvent("onresize");
1269
+ this.propagateEvent( "onresize" );
1190
1270
  }
1191
1271
 
1192
1272
  /**
@@ -1196,7 +1276,9 @@ console.warn( 'Script "build/lexgui.js" is depracated and will be removed soon.
1196
1276
  extend() {
1197
1277
 
1198
1278
  if( this.split_extended )
1199
- return;
1279
+ {
1280
+ return;
1281
+ }
1200
1282
 
1201
1283
  let [area1, area2] = this.sections;
1202
1284
  this.split_extended = true;
@@ -1866,11 +1948,15 @@ console.warn( 'Script "build/lexgui.js" is depracated and will be removed soon.
1866
1948
 
1867
1949
  const tabEl = this.tabDOMs[ name ];
1868
1950
 
1869
- if(!tabEl || tabEl.fixed)
1870
- return;
1951
+ if( !tabEl || tabEl.fixed )
1952
+ {
1953
+ return;
1954
+ }
1871
1955
 
1872
1956
  if( this.onclose )
1957
+ {
1873
1958
  this.onclose( name );
1959
+ }
1874
1960
 
1875
1961
  // Delete tab element
1876
1962
  this.tabDOMs[ name ].remove();
@@ -1881,11 +1967,12 @@ console.warn( 'Script "build/lexgui.js" is depracated and will be removed soon.
1881
1967
  delete this.tabs[ name ];
1882
1968
 
1883
1969
  // Select last tab
1884
- const last_tab = this.root.lastChild;
1885
- if(last_tab && !last_tab.fixed)
1970
+ const lastTab = this.root.lastChild;
1971
+ if( lastTab && !lastTab.fixed )
1972
+ {
1886
1973
  this.root.lastChild.click();
1974
+ }
1887
1975
  }
1888
-
1889
1976
  }
1890
1977
 
1891
1978
  LX.Tabs = Tabs;
@@ -2451,6 +2538,9 @@ console.warn( 'Script "build/lexgui.js" is depracated and will be removed soon.
2451
2538
  static CONTENT = 20;
2452
2539
  static CUSTOM = 21;
2453
2540
  static SEPARATOR = 22;
2541
+ static KNOB = 23;
2542
+ static SIZE = 24;
2543
+ static PAD = 25;
2454
2544
 
2455
2545
  static NO_CONTEXT_TYPES = [
2456
2546
  Widget.BUTTON,
@@ -2459,7 +2549,7 @@ console.warn( 'Script "build/lexgui.js" is depracated and will be removed soon.
2459
2549
  Widget.PROGRESS
2460
2550
  ];
2461
2551
 
2462
- constructor(name, type, options) {
2552
+ constructor( name, type, options ) {
2463
2553
  this.name = name;
2464
2554
  this.type = type;
2465
2555
  this.options = options;
@@ -2467,10 +2557,12 @@ console.warn( 'Script "build/lexgui.js" is depracated and will be removed soon.
2467
2557
 
2468
2558
  value() {
2469
2559
 
2470
- if(this.onGetValue)
2560
+ if( this.onGetValue )
2561
+ {
2471
2562
  return this.onGetValue();
2563
+ }
2472
2564
 
2473
- console.warn("Can't get value of " + this.typeName());
2565
+ console.warn( "Can't get value of " + this.typeName() );
2474
2566
  }
2475
2567
 
2476
2568
  set( value, skipCallback = false ) {
@@ -2506,14 +2598,16 @@ console.warn( 'Script "build/lexgui.js" is depracated and will be removed soon.
2506
2598
 
2507
2599
  paste() {
2508
2600
  if( !this._can_paste() )
2509
- return;
2601
+ {
2602
+ return;
2603
+ }
2510
2604
 
2511
2605
  this.set(navigator.clipboard.data);
2512
2606
  }
2513
2607
 
2514
2608
  typeName() {
2515
2609
 
2516
- switch(this.type) {
2610
+ switch( this.type ) {
2517
2611
  case Widget.TEXT: return "Text";
2518
2612
  case Widget.TEXTAREA: return "TextArea";
2519
2613
  case Widget.BUTTON: return "Button";
@@ -2530,6 +2624,9 @@ console.warn( 'Script "build/lexgui.js" is depracated and will be removed soon.
2530
2624
  case Widget.LIST: return "List";
2531
2625
  case Widget.TAGS: return "Tags";
2532
2626
  case Widget.CURVE: return "Curve";
2627
+ case Widget.KNOB: return "Knob";
2628
+ case Widget.SIZE: return "Size";
2629
+ case Widget.PAD: return "Pad";
2533
2630
  case Widget.CUSTOM: return this.customName;
2534
2631
  }
2535
2632
  }
@@ -2624,40 +2721,50 @@ console.warn( 'Script "build/lexgui.js" is depracated and will be removed soon.
2624
2721
  custom_widgets.className = "lexcustomitems";
2625
2722
  custom_widgets.toggleAttribute('hidden', true);
2626
2723
 
2627
- element.appendChild(container);
2628
- element.appendChild(custom_widgets);
2629
-
2630
- if( instance ) {
2631
-
2724
+ element.appendChild( container );
2725
+ element.appendChild( custom_widgets );
2726
+
2727
+ if( instance )
2728
+ {
2729
+
2632
2730
  this.queue( custom_widgets );
2633
2731
 
2634
- const on_instance_changed = (key, value, event) => {
2635
- instance[key] = value;
2636
- this._trigger( new IEvent(name, instance, event), callback );
2732
+ const on_instance_changed = ( key, value, event ) => {
2733
+ instance[ key ] = value;
2734
+ this._trigger( new IEvent( name, instance, event ), callback );
2637
2735
  };
2638
2736
 
2639
2737
  for( let key in default_instance )
2640
2738
  {
2641
- const value = instance[key] ?? default_instance[key];
2739
+ const value = instance[ key ] ?? default_instance[ key ];
2642
2740
 
2643
- switch(value.constructor) {
2741
+ switch( value.constructor )
2742
+ {
2644
2743
  case String:
2645
- if(value[0] === '#')
2646
- this.addColor(key, value, on_instance_changed.bind(this, key));
2744
+ if( value[ 0 ] === '#' )
2745
+ {
2746
+ this.addColor( key, value, on_instance_changed.bind( this, key ) );
2747
+ }
2647
2748
  else
2648
- this.addText(key, value, on_instance_changed.bind(this, key));
2749
+ {
2750
+ this.addText( key, value, on_instance_changed.bind( this, key ) );
2751
+ }
2649
2752
  break;
2650
2753
  case Number:
2651
- this.addNumber(key, value, on_instance_changed.bind(this, key));
2754
+ this.addNumber( key, value, on_instance_changed.bind( this, key ) );
2652
2755
  break;
2653
2756
  case Boolean:
2654
- this.addCheckbox(key, value, on_instance_changed.bind(this, key));
2757
+ this.addCheckbox( key, value, on_instance_changed.bind( this, key ) );
2655
2758
  break;
2656
2759
  case Array:
2657
2760
  if( value.length > 4 )
2658
- this.addArray(key, value, on_instance_changed.bind(this, key));
2761
+ {
2762
+ this.addArray( key, value, on_instance_changed.bind( this, key ) );
2763
+ }
2659
2764
  else
2660
- this._add_vector(value.length, key, value, on_instance_changed.bind(this, key));
2765
+ {
2766
+ this._add_vector( value.length, key, value, on_instance_changed.bind( this, key ) );
2767
+ }
2661
2768
  break;
2662
2769
  }
2663
2770
  }
@@ -2695,37 +2802,40 @@ console.warn( 'Script "build/lexgui.js" is depracated and will be removed soon.
2695
2802
  _create_item( parent, node, level = 0, selectedId ) {
2696
2803
 
2697
2804
  const that = this;
2698
- const node_filter_input = this.domEl.querySelector("#lexnodetree_filter");
2805
+ const node_filter_input = this.domEl.querySelector( "#lexnodetree_filter" );
2699
2806
 
2700
2807
  node.children = node.children ?? [];
2701
- if(node_filter_input && !node.id.includes(node_filter_input.value) || (selectedId != undefined) && selectedId != node.id)
2808
+ if( node_filter_input && !node.id.includes( node_filter_input.value ) || (selectedId != undefined) && selectedId != node.id )
2702
2809
  {
2703
2810
  for( var i = 0; i < node.children.length; ++i )
2704
- this._create_item( node, node.children[i], level + 1, selectedId );
2811
+ {
2812
+ this._create_item( node, node.children[ i ], level + 1, selectedId );
2813
+ }
2705
2814
  return;
2706
2815
  }
2707
2816
 
2708
- const list = this.domEl.querySelector("ul");
2817
+ const list = this.domEl.querySelector( 'ul' );
2709
2818
 
2710
2819
  node.visible = node.visible ?? true;
2711
2820
  node.parent = parent;
2712
- let is_parent = node.children.length > 0;
2713
- let is_selected = this.selected.indexOf( node ) > -1;
2821
+ let isParent = node.children.length > 0;
2822
+ let isSelected = this.selected.indexOf( node ) > -1;
2714
2823
 
2715
- if( this.options.only_folders ) {
2824
+ if( this.options.only_folders )
2825
+ {
2716
2826
  let has_folders = false;
2717
2827
  node.children.forEach( c => has_folders |= (c.type == 'folder') );
2718
- is_parent = !!has_folders;
2828
+ isParent = !!has_folders;
2719
2829
  }
2720
2830
 
2721
2831
  let item = document.createElement('li');
2722
- item.className = "lextreeitem " + "datalevel" + level + (is_parent ? " parent" : "") + (is_selected ? " selected" : "");
2832
+ item.className = "lextreeitem " + "datalevel" + level + (isParent ? " parent" : "") + (isSelected ? " selected" : "");
2723
2833
  item.id = LX.getSupportedDOMName( node.id );
2724
2834
  item.tabIndex = "0";
2725
2835
 
2726
2836
  // Select hierarchy icon
2727
2837
  let icon = (this.options.skip_default_icon ?? true) ? "" : "fa-solid fa-square"; // Default: no childs
2728
- if( is_parent ) icon = node.closed ? "fa-solid fa-caret-right" : "fa-solid fa-caret-down";
2838
+ if( isParent ) icon = node.closed ? "fa-solid fa-caret-right" : "fa-solid fa-caret-down";
2729
2839
  item.innerHTML = "<a class='" + icon + " hierarchy'></a>";
2730
2840
 
2731
2841
  // Add display icon
@@ -2745,18 +2855,20 @@ console.warn( 'Script "build/lexgui.js" is depracated and will be removed soon.
2745
2855
 
2746
2856
  item.innerHTML += (node.rename ? "" : node.id);
2747
2857
 
2748
- item.setAttribute('draggable', true);
2749
- item.style.paddingLeft = ((is_parent ? 0 : 3 ) + (3 + (level+1) * 15)) + "px";
2750
- list.appendChild(item);
2858
+ item.setAttribute( 'draggable', true );
2859
+ item.style.paddingLeft = ((isParent ? 0 : 3 ) + (3 + (level+1) * 15)) + "px";
2860
+ list.appendChild( item );
2751
2861
 
2752
2862
  // Callbacks
2753
2863
  item.addEventListener("click", e => {
2754
- if( handled ) {
2864
+ if( handled )
2865
+ {
2755
2866
  handled = false;
2756
2867
  return;
2757
2868
  }
2758
2869
 
2759
- if(!e.shiftKey) {
2870
+ if( !e.shiftKey )
2871
+ {
2760
2872
  list.querySelectorAll("li").forEach( e => { e.classList.remove('selected'); } );
2761
2873
  this.selected.length = 0;
2762
2874
  }
@@ -2772,16 +2884,18 @@ console.warn( 'Script "build/lexgui.js" is depracated and will be removed soon.
2772
2884
  }
2773
2885
 
2774
2886
  // Only Show children...
2775
- if(is_parent && node.id.length > 1 /* Strange case... */) {
2887
+ if(isParent && node.id.length > 1 /* Strange case... */) {
2776
2888
  node.closed = false;
2777
- if(that.onevent) {
2778
- const event = new TreeEvent(TreeEvent.NODE_CARETCHANGED, node, node.closed);
2889
+ if( that.onevent )
2890
+ {
2891
+ const event = new TreeEvent( TreeEvent.NODE_CARETCHANGED, node, node.closed );
2779
2892
  that.onevent( event );
2780
2893
  }
2781
2894
  that.frefresh( node.id );
2782
2895
  }
2783
2896
 
2784
- if(that.onevent) {
2897
+ if( that.onevent )
2898
+ {
2785
2899
  const event = new TreeEvent(TreeEvent.NODE_SELECTED, e.shiftKey ? this.selected : node );
2786
2900
  event.multiple = e.shiftKey;
2787
2901
  that.onevent( event );
@@ -2789,37 +2903,110 @@ console.warn( 'Script "build/lexgui.js" is depracated and will be removed soon.
2789
2903
  });
2790
2904
 
2791
2905
  item.addEventListener("dblclick", function() {
2906
+
2792
2907
  if( that.options.rename ?? true )
2793
2908
  {
2794
2909
  // Trigger rename
2795
2910
  node.rename = true;
2796
2911
  that.refresh();
2797
2912
  }
2913
+
2798
2914
  if( that.onevent )
2799
2915
  {
2800
- const event = new TreeEvent(TreeEvent.NODE_DBLCLICKED, node);
2916
+ const event = new TreeEvent( TreeEvent.NODE_DBLCLICKED, node );
2801
2917
  that.onevent( event );
2802
2918
  }
2803
2919
  });
2804
2920
 
2805
- item.addEventListener("contextmenu", e => {
2921
+ item.addEventListener( "contextmenu", e => {
2922
+
2806
2923
  e.preventDefault();
2807
- if(that.onevent) {
2808
- const event = new TreeEvent(TreeEvent.NODE_CONTEXTMENU, this.selected.length > 1 ? this.selected : node, e);
2809
- event.multiple = this.selected.length > 1;
2810
- that.onevent( event );
2924
+
2925
+ if( !that.onevent )
2926
+ {
2927
+ return;
2928
+ }
2929
+
2930
+ const event = new TreeEvent(TreeEvent.NODE_CONTEXTMENU, this.selected.length > 1 ? this.selected : node, e);
2931
+ event.multiple = this.selected.length > 1;
2932
+
2933
+ LX.addContextMenu( event.multiple ? "Selected Nodes" : event.node.id, event.value, m => {
2934
+ event.panel = m;
2935
+ });
2936
+
2937
+ that.onevent( event );
2938
+
2939
+ if( ( this.options.addDefault ?? false ) == true )
2940
+ {
2941
+ if( event.panel.items )
2942
+ {
2943
+ event.panel.add( "" );
2944
+ }
2945
+
2946
+ event.panel.add( "Select Children", () => {
2947
+
2948
+ const selectChildren = ( n ) => {
2949
+
2950
+ if( n.closed )
2951
+ {
2952
+ return;
2953
+ }
2954
+
2955
+ for( let child of n.children ?? [] )
2956
+ {
2957
+ if( !child )
2958
+ {
2959
+ continue;
2960
+ }
2961
+
2962
+ let nodeItem = this.domEl.querySelector( '#' + child.id );
2963
+ nodeItem.classList.add('selected');
2964
+ this.selected.push( child );
2965
+ selectChildren( child );
2966
+ }
2967
+ };
2968
+
2969
+ // Add childs of the clicked node
2970
+ selectChildren( node );
2971
+ } );
2972
+
2973
+ event.panel.add( "Delete", { callback: () => {
2974
+
2975
+ // It's the root node
2976
+ if( !node.parent )
2977
+ {
2978
+ return;
2979
+ }
2980
+
2981
+ if( that.onevent ) {
2982
+ const event = new TreeEvent( TreeEvent.NODE_DELETED, node, e );
2983
+ that.onevent( event );
2984
+ }
2985
+
2986
+ // Delete nodes now
2987
+ let childs = node.parent.children;
2988
+ const index = childs.indexOf( node );
2989
+ childs.splice( index, 1 );
2990
+
2991
+ this.refresh();
2992
+ } } );
2811
2993
  }
2812
2994
  });
2813
2995
 
2814
2996
  item.addEventListener("keydown", e => {
2815
- if(node.rename)
2816
- return;
2997
+
2998
+ if( node.rename )
2999
+ {
3000
+ return;
3001
+ }
3002
+
2817
3003
  e.preventDefault();
3004
+
2818
3005
  if( e.key == "Delete" )
2819
3006
  {
2820
3007
  // Send event now so we have the info in selected array..
2821
- if(that.onevent) {
2822
- const event = new TreeEvent(TreeEvent.NODE_DELETED, this.selected.length > 1 ? this.selected : node, e);
3008
+ if( that.onevent ) {
3009
+ const event = new TreeEvent( TreeEvent.NODE_DELETED, this.selected.length > 1 ? this.selected : node, e );
2823
3010
  event.multiple = this.selected.length > 1;
2824
3011
  that.onevent( event );
2825
3012
  }
@@ -2837,10 +3024,13 @@ console.warn( 'Script "build/lexgui.js" is depracated and will be removed soon.
2837
3024
  }
2838
3025
  else if( e.key == "ArrowUp" || e.key == "ArrowDown" ) // Unique or zero selected
2839
3026
  {
2840
- var selected = this.selected.length > 1 ? (e.key == "ArrowUp" ? this.selected.shift() : this.selected.pop()) : this.selected[0];
2841
- var el = this.domEl.querySelector("#" + LX.getSupportedDOMName( selected.id ) );
3027
+ var selected = this.selected.length > 1 ? ( e.key == "ArrowUp" ? this.selected.shift() : this.selected.pop() ) : this.selected[ 0 ];
3028
+ var el = this.domEl.querySelector( "#" + LX.getSupportedDOMName( selected.id ) );
2842
3029
  var sibling = e.key == "ArrowUp" ? el.previousSibling : el.nextSibling;
2843
- if( sibling ) sibling.click();
3030
+ if( sibling )
3031
+ {
3032
+ sibling.click();
3033
+ }
2844
3034
  }
2845
3035
  });
2846
3036
 
@@ -2946,7 +3136,7 @@ console.warn( 'Script "build/lexgui.js" is depracated and will be removed soon.
2946
3136
  let handled = false;
2947
3137
 
2948
3138
  // Show/hide children
2949
- if(is_parent) {
3139
+ if(isParent) {
2950
3140
  item.querySelector('a.hierarchy').addEventListener("click", function(e) {
2951
3141
 
2952
3142
  handled = true;
@@ -3084,19 +3274,25 @@ console.warn( 'Script "build/lexgui.js" is depracated and will be removed soon.
3084
3274
  getValue( name ) {
3085
3275
 
3086
3276
  let widget = this.widgets[ name ];
3087
- if(!widget)
3088
- throw("No widget called " + name);
3277
+
3278
+ if( !widget )
3279
+ {
3280
+ throw( "No widget called " + name );
3281
+ }
3089
3282
 
3090
3283
  return widget.value();
3091
3284
  }
3092
3285
 
3093
- setValue( name, value ) {
3286
+ setValue( name, value, skipCallback ) {
3094
3287
 
3095
3288
  let widget = this.widgets[ name ];
3096
- if(!widget)
3097
- throw("No widget called " + name);
3098
3289
 
3099
- return widget.set(value);
3290
+ if( !widget )
3291
+ {
3292
+ throw( "No widget called " + name );
3293
+ }
3294
+
3295
+ return widget.set( value, skipCallback );
3100
3296
  }
3101
3297
 
3102
3298
  /**
@@ -3275,9 +3471,9 @@ console.warn( 'Script "build/lexgui.js" is depracated and will be removed soon.
3275
3471
  return (typeof arg == 'undefined' ? def : arg);
3276
3472
  }
3277
3473
 
3278
- static _dispatch_event( element, type, bubbles, cancelable ) {
3279
- let event = new Event(type, { 'bubbles': bubbles, 'cancelable': cancelable });
3280
- element.dispatchEvent(event);
3474
+ static _dispatch_event( element, type, data, bubbles, cancelable ) {
3475
+ let event = new CustomEvent( type, { 'detail': data, 'bubbles': bubbles, 'cancelable': cancelable } );
3476
+ element.dispatchEvent( event );
3281
3477
  }
3282
3478
 
3283
3479
  static _add_reset_property( container, callback ) {
@@ -3285,8 +3481,8 @@ console.warn( 'Script "build/lexgui.js" is depracated and will be removed soon.
3285
3481
  domEl.style.display = "none";
3286
3482
  domEl.style.marginRight = "6px";
3287
3483
  domEl.className = "lexicon fa fa-rotate-left";
3288
- domEl.addEventListener("click", callback);
3289
- container.appendChild(domEl);
3484
+ domEl.addEventListener( "click", callback );
3485
+ container.appendChild( domEl );
3290
3486
  return domEl;
3291
3487
  }
3292
3488
 
@@ -3296,39 +3492,45 @@ console.warn( 'Script "build/lexgui.js" is depracated and will be removed soon.
3296
3492
 
3297
3493
  create_widget( name, type, options = {} ) {
3298
3494
 
3299
- let widget = new Widget(name, type, options);
3495
+ let widget = new Widget( name, type, options );
3300
3496
 
3301
- let element = document.createElement('div');
3497
+ let element = document.createElement( 'div' );
3302
3498
  element.className = "lexwidget";
3303
- if(options.id)
3304
- element.id = options.id;
3305
- if(options.className)
3499
+ element.id = options.id ?? "";
3500
+ element.title = options.title ?? "";
3501
+
3502
+ if( options.className )
3503
+ {
3306
3504
  element.className += " " + options.className;
3307
- if(options.title)
3308
- element.title = options.title;
3505
+ }
3309
3506
 
3310
3507
  if( type != Widget.TITLE )
3311
3508
  {
3312
3509
  element.style.width = "calc(100% - " + (this.current_branch || type == Widget.FILE ? 10 : 20) + "px)";
3313
- if( options.width ) {
3510
+
3511
+ if( options.width )
3512
+ {
3314
3513
  element.style.width = element.style.minWidth = options.width;
3315
3514
  }
3316
- if( options.maxWidth ) {
3515
+ if( options.maxWidth )
3516
+ {
3317
3517
  element.style.maxWidth = options.maxWidth;
3318
3518
  }
3319
- if( options.minWidth ) {
3519
+ if( options.minWidth )
3520
+ {
3320
3521
  element.style.minWidth = options.minWidth;
3321
3522
  }
3322
- if( options.height ) {
3523
+ if( options.height )
3524
+ {
3323
3525
  element.style.height = element.style.minHeight = options.height;
3324
3526
  }
3325
3527
  }
3326
3528
 
3327
- if(name != undefined) {
3328
-
3329
- if(!(options.no_name ?? false) )
3529
+ if( name != undefined )
3530
+ {
3531
+ if( !(options.no_name ?? false) )
3330
3532
  {
3331
- let domName = document.createElement('div');
3533
+ let domName = document.createElement( 'div' );
3332
3534
  domName.className = "lexwidgetname";
3333
3535
  if( options.justifyName )
3334
3536
  {
@@ -3341,22 +3543,27 @@ console.warn( 'Script "build/lexgui.js" is depracated and will be removed soon.
3341
3543
  element.domName = domName;
3342
3544
 
3343
3545
  // Copy-paste info
3344
- domName.addEventListener('contextmenu', function(e) {
3546
+ domName.addEventListener('contextmenu', function( e ) {
3345
3547
  e.preventDefault();
3346
- widget.oncontextmenu(e);
3548
+ widget.oncontextmenu( e );
3347
3549
  });
3348
3550
  }
3349
3551
 
3350
3552
  this.widgets[ name ] = widget;
3351
3553
  }
3352
3554
 
3353
- if(options.signal)
3555
+ if( options.signal )
3354
3556
  {
3355
- if(!name) {
3356
- if(!this.signals)
3557
+ if( !name )
3558
+ {
3559
+ if( !this.signals )
3560
+ {
3357
3561
  this.signals = [];
3358
- this.signals.push({[options.signal]: widget})
3562
+ }
3563
+
3564
+ this.signals.push( { [ options.signal ]: widget } )
3359
3565
  }
3566
+
3360
3567
  LX.addSignal( options.signal, widget );
3361
3568
  }
3362
3569
 
@@ -4843,7 +5050,7 @@ console.warn( 'Script "build/lexgui.js" is depracated and will be removed soon.
4843
5050
  flag.className = "checkbox " + (flag.value ? "on" : "");
4844
5051
  flag.id = "checkbox"+simple_guidGenerator();
4845
5052
  flag.innerHTML = "<a class='fa-solid fa-check' style='display: " + (flag.value ? "block" : "none") + "'></a>";
4846
-
5053
+
4847
5054
  if( options.disabled ) {
4848
5055
  flag.disabled = true;
4849
5056
  toggle.className += " disabled";
@@ -5011,6 +5218,9 @@ console.warn( 'Script "build/lexgui.js" is depracated and will be removed soon.
5011
5218
  * precision: The number of digits to appear after the decimal point
5012
5219
  * min, max: Min and Max values for the input
5013
5220
  * skipSlider: If there are min and max values, skip the slider
5221
+ * units: Unit as string added to the end of the value
5222
+ * onPress: Callback function on mouse down
5223
+ * onRelease: Callback function on mouse is released
5014
5224
  */
5015
5225
 
5016
5226
  addNumber( name, value, callback, options = {} ) {
@@ -5020,8 +5230,9 @@ console.warn( 'Script "build/lexgui.js" is depracated and will be removed soon.
5020
5230
  widget.onGetValue = () => {
5021
5231
  return +vecinput.value;
5022
5232
  };
5233
+
5023
5234
  widget.onSetValue = ( newValue, skipCallback ) => {
5024
- vecinput.value = newValue;
5235
+ vecinput.value = round( newValue, options.precision );
5025
5236
  Panel._dispatch_event( vecinput, "change", skipCallback );
5026
5237
  };
5027
5238
 
@@ -5046,45 +5257,82 @@ console.warn( 'Script "build/lexgui.js" is depracated and will be removed soon.
5046
5257
  box.className = "numberbox";
5047
5258
 
5048
5259
  let vecinput = document.createElement( 'input' );
5260
+ vecinput.id = "number_" + simple_guidGenerator();
5049
5261
  vecinput.className = "vecinput";
5050
5262
  vecinput.min = options.min ?? -1e24;
5051
5263
  vecinput.max = options.max ?? 1e24;
5052
5264
  vecinput.step = options.step ?? "any";
5053
5265
  vecinput.type = "number";
5054
- vecinput.id = "number_" + simple_guidGenerator();
5055
5266
 
5056
5267
  if( value.constructor == Number )
5057
5268
  {
5058
5269
  value = clamp( value, +vecinput.min, +vecinput.max );
5059
- value = options.precision ? round( value, options.precision ) : value;
5270
+ value = round( value, options.precision );
5060
5271
  }
5061
5272
 
5062
5273
  vecinput.value = vecinput.iValue = value;
5063
5274
  box.appendChild( vecinput );
5064
5275
 
5065
- let drag_icon = document.createElement( 'a' );
5066
- drag_icon.className = "fa-solid fa-arrows-up-down drag-icon hidden";
5067
- box.appendChild( drag_icon );
5276
+ if( options.units )
5277
+ {
5278
+ let unitSpan = document.createElement( 'span' );
5279
+ unitSpan.className = "lexunit";
5280
+ unitSpan.innerText = options.units;
5281
+ unitSpan.style.left = measureRealWidth( vecinput.value ) + "px";
5282
+ vecinput.unitSpan = unitSpan;
5283
+ box.appendChild( unitSpan );
5284
+ }
5068
5285
 
5069
- if( options.disabled ) {
5286
+ let dragIcon = document.createElement( 'a' );
5287
+ dragIcon.className = "fa-solid fa-arrows-up-down drag-icon hidden";
5288
+ box.appendChild( dragIcon );
5289
+
5290
+ if( options.disabled )
5291
+ {
5070
5292
  vecinput.disabled = true;
5071
5293
  }
5072
5294
 
5073
- // add slider below
5074
- if( !options.skipSlider && options.min !== undefined && options.max !== undefined ) {
5295
+ // Add slider below
5296
+ if( !options.skipSlider && options.min !== undefined && options.max !== undefined )
5297
+ {
5075
5298
  let slider = document.createElement( 'input' );
5076
5299
  slider.className = "lexinputslider";
5077
- slider.step = options.step ?? 1;
5078
5300
  slider.min = options.min;
5079
5301
  slider.max = options.max;
5302
+ slider.step = options.step ?? 1;
5080
5303
  slider.type = "range";
5081
5304
  slider.value = value;
5305
+
5082
5306
  slider.addEventListener( "input", function( e ) {
5083
5307
  let new_value = +this.valueAsNumber;
5084
- vecinput.value = ( +new_value ).toFixed( 4 ).replace( /([0-9]+(\.[0-9]+[1-9])?)(\.?0+$)/, '$1' );
5308
+ vecinput.value = round( new_value, options.precision );
5085
5309
  Panel._dispatch_event( vecinput, "change" );
5086
5310
  }, false );
5311
+
5312
+ slider.addEventListener( "mousedown", function( e ) {
5313
+ if( options.onPress )
5314
+ {
5315
+ options.onPress.bind( slider )( e, slider );
5316
+ }
5317
+ }, false );
5318
+
5319
+ slider.addEventListener( "mouseup", function( e ) {
5320
+ if( options.onRelease )
5321
+ {
5322
+ options.onRelease.bind( slider )( e, slider );
5323
+ }
5324
+ }, false );
5325
+
5087
5326
  box.appendChild( slider );
5327
+
5328
+ // Method to change min, max, step parameters
5329
+ widget.setLimits = ( newMin, newMax, newStep ) => {
5330
+ vecinput.min = slider.min = newMin ?? vecinput.min;
5331
+ vecinput.max = slider.max = newMax ?? vecinput.max;
5332
+ vecinput.step = newStep ?? vecinput.step;
5333
+ slider.step = newStep ?? slider.step;
5334
+ Panel._dispatch_event( vecinput, "change", true );
5335
+ };
5088
5336
  }
5089
5337
 
5090
5338
  // Add wheel input
@@ -5092,30 +5340,42 @@ console.warn( 'Script "build/lexgui.js" is depracated and will be removed soon.
5092
5340
  vecinput.addEventListener( "wheel", function( e ) {
5093
5341
  e.preventDefault();
5094
5342
  if( this !== document.activeElement )
5343
+ {
5095
5344
  return;
5345
+ }
5096
5346
  let mult = options.step ?? 1;
5097
5347
  if( e.shiftKey ) mult *= 10;
5098
5348
  else if( e.altKey ) mult *= 0.1;
5099
5349
  let new_value = ( +this.valueAsNumber - mult * ( e.deltaY > 0 ? 1 : -1 ) );
5100
- this.value = ( +new_value ).toFixed( 4 ).replace( /([0-9]+(\.[0-9]+[1-9])?)(\.?0+$)/, '$1' );
5350
+ this.value = round( new_value, options.precision );
5101
5351
  Panel._dispatch_event(vecinput, "change");
5102
5352
  }, { passive: false });
5103
5353
 
5104
5354
  vecinput.addEventListener( "change", e => {
5105
5355
 
5106
5356
  if( isNaN( e.target.valueAsNumber ) )
5357
+ {
5107
5358
  return;
5359
+ }
5108
5360
 
5109
5361
  const skipCallback = e.detail;
5110
5362
 
5111
5363
  let val = e.target.value = clamp( +e.target.valueAsNumber, +vecinput.min, +vecinput.max );
5112
5364
  val = options.precision ? round( val, options.precision ) : val;
5113
- // update slider!
5365
+
5366
+ // Update slider!
5114
5367
  if( box.querySelector( ".lexinputslider" ) )
5368
+ {
5115
5369
  box.querySelector( ".lexinputslider" ).value = val;
5370
+ }
5116
5371
 
5117
5372
  vecinput.value = val;
5118
5373
 
5374
+ if( options.units )
5375
+ {
5376
+ vecinput.unitSpan.style.left = measureRealWidth( vecinput.value ) + "px";
5377
+ }
5378
+
5119
5379
  // Reset button (default value)
5120
5380
  if( !skipCallback )
5121
5381
  {
@@ -5132,28 +5392,40 @@ console.warn( 'Script "build/lexgui.js" is depracated and will be removed soon.
5132
5392
 
5133
5393
  var that = this;
5134
5394
  var lastY = 0;
5135
- function inner_mousedown(e) {
5136
- if(document.activeElement == vecinput) return;
5395
+
5396
+ function inner_mousedown( e )
5397
+ {
5398
+ if( document.activeElement == vecinput )
5399
+ {
5400
+ return;
5401
+ }
5402
+
5137
5403
  var doc = that.root.ownerDocument;
5138
- doc.addEventListener("mousemove",inner_mousemove);
5139
- doc.addEventListener("mouseup",inner_mouseup);
5404
+ doc.addEventListener( 'mousemove', inner_mousemove );
5405
+ doc.addEventListener( 'mouseup', inner_mouseup );
5140
5406
  lastY = e.pageY;
5141
- document.body.classList.add('nocursor');
5142
- document.body.classList.add('noevents');
5143
- drag_icon.classList.remove('hidden');
5407
+ document.body.classList.add( 'nocursor' );
5408
+ document.body.classList.add( 'noevents' );
5409
+ dragIcon.classList.remove( 'hidden' );
5144
5410
  e.stopImmediatePropagation();
5145
5411
  e.stopPropagation();
5412
+
5413
+ if( options.onPress )
5414
+ {
5415
+ options.onPress.bind( vecinput )( e, vecinput );
5416
+ }
5146
5417
  }
5147
5418
 
5148
- function inner_mousemove(e) {
5149
- if (lastY != e.pageY) {
5419
+ function inner_mousemove( e )
5420
+ {
5421
+ if ( lastY != e.pageY ) {
5150
5422
  let dt = lastY - e.pageY;
5151
5423
  let mult = options.step ?? 1;
5152
- if(e.shiftKey) mult *= 10;
5153
- else if(e.altKey) mult *= 0.1;
5154
- let new_value = (+vecinput.valueAsNumber + mult * dt);
5155
- vecinput.value = (+new_value).toFixed(4).replace(/([0-9]+(\.[0-9]+[1-9])?)(\.?0+$)/,'$1');
5156
- Panel._dispatch_event(vecinput, "change");
5424
+ if( e.shiftKey ) mult *= 10;
5425
+ else if( e.altKey ) mult *= 0.1;
5426
+ let new_value = ( +vecinput.valueAsNumber + mult * dt );
5427
+ vecinput.value = ( +new_value ).toFixed( 4 ).replace( /([0-9]+(\.[0-9]+[1-9])?)(\.?0+$)/, '$1' );
5428
+ Panel._dispatch_event( vecinput, "change" );
5157
5429
  }
5158
5430
 
5159
5431
  lastY = e.pageY;
@@ -5161,20 +5433,27 @@ console.warn( 'Script "build/lexgui.js" is depracated and will be removed soon.
5161
5433
  e.preventDefault();
5162
5434
  }
5163
5435
 
5164
- function inner_mouseup(e) {
5436
+ function inner_mouseup( e )
5437
+ {
5165
5438
  var doc = that.root.ownerDocument;
5166
- doc.removeEventListener("mousemove",inner_mousemove);
5167
- doc.removeEventListener("mouseup",inner_mouseup);
5168
- document.body.classList.remove('nocursor');
5169
- document.body.classList.remove('noevents');
5170
- drag_icon.classList.add('hidden');
5439
+ doc.removeEventListener( 'mousemove', inner_mousemove );
5440
+ doc.removeEventListener( 'mouseup', inner_mouseup );
5441
+ document.body.classList.remove( 'nocursor' );
5442
+ document.body.classList.remove( 'noevents' );
5443
+ dragIcon.classList.add( 'hidden' );
5444
+
5445
+ if( options.onRelease )
5446
+ {
5447
+ options.onRelease.bind( vecinput )( e, vecinput );
5448
+ }
5171
5449
  }
5172
5450
 
5173
- container.appendChild(box);
5174
- element.appendChild(container);
5451
+ container.appendChild( box );
5452
+ element.appendChild( container );
5175
5453
 
5176
5454
  // Remove branch padding and margins
5177
- if(!widget.name) {
5455
+ if( !widget.name )
5456
+ {
5178
5457
  element.className += " noname";
5179
5458
  container.style.width = "100%";
5180
5459
  }
@@ -5182,14 +5461,15 @@ console.warn( 'Script "build/lexgui.js" is depracated and will be removed soon.
5182
5461
  return widget;
5183
5462
  }
5184
5463
 
5185
- static VECTOR_COMPONENTS = {0: 'x', 1: 'y', 2: 'z', 3: 'w'};
5464
+ static VECTOR_COMPONENTS = { 0: 'x', 1: 'y', 2: 'z', 3: 'w' };
5186
5465
 
5187
5466
  _add_vector( num_components, name, value, callback, options = {} ) {
5188
5467
 
5189
5468
  num_components = clamp( num_components, 2, 4 );
5190
5469
  value = value ?? new Array( num_components ).fill( 0 );
5191
5470
 
5192
- if( !name ) {
5471
+ if( !name )
5472
+ {
5193
5473
  throw( "Set Widget Name!" );
5194
5474
  }
5195
5475
 
@@ -5199,14 +5479,23 @@ console.warn( 'Script "build/lexgui.js" is depracated and will be removed soon.
5199
5479
  let inputs = element.querySelectorAll( "input" );
5200
5480
  let value = [];
5201
5481
  for( var v of inputs )
5482
+ {
5202
5483
  value.push( +v.value );
5484
+ }
5203
5485
  return value;
5204
5486
  };
5487
+
5205
5488
  widget.onSetValue = ( newValue, skipCallback ) => {
5206
5489
  const inputs = element.querySelectorAll( ".vecinput" );
5207
- for( var i = 0; i < inputs.length; ++i ) {
5490
+ if( inputs.length == newValue.length )
5491
+ {
5492
+ console.error( "Input length does not match vector length." );
5493
+ return;
5494
+ }
5495
+
5496
+ for( let i = 0; i < inputs.length; ++i ) {
5208
5497
  let value = newValue[ i ];
5209
- inputs[ i ].value = value ?? 0;
5498
+ inputs[ i ].value = round( value, options.precision ) ?? 0;
5210
5499
  Panel._dispatch_event( inputs[ i ], "change", skipCallback );
5211
5500
  }
5212
5501
  };
@@ -5224,7 +5513,7 @@ console.warn( 'Script "build/lexgui.js" is depracated and will be removed soon.
5224
5513
 
5225
5514
  // Add widget value
5226
5515
 
5227
- var container = document.createElement('div');
5516
+ var container = document.createElement( 'div' );
5228
5517
  container.className = "lexvector";
5229
5518
  container.style.width = "calc( 100% - " + LX.DEFAULT_NAME_WIDTH + ")";
5230
5519
 
@@ -5246,21 +5535,21 @@ console.warn( 'Script "build/lexgui.js" is depracated and will be removed soon.
5246
5535
  if( value[ i ].constructor == Number )
5247
5536
  {
5248
5537
  value[ i ] = clamp(value[ i ], +vecinput.min, +vecinput.max);
5249
- value[ i ] = options.precision ? round(value[ i ], options.precision) : value[ i ];
5538
+ value[ i ] = round( value[ i ], options.precision );
5250
5539
  }
5251
5540
 
5252
5541
  vecinput.value = vecinput.iValue = value[ i ];
5253
5542
 
5254
- let drag_icon = document.createElement( 'a' );
5255
- drag_icon.className = "fa-solid fa-arrows-up-down drag-icon hidden";
5256
- box.appendChild( drag_icon );
5543
+ let dragIcon = document.createElement( 'a' );
5544
+ dragIcon.className = "fa-solid fa-arrows-up-down drag-icon hidden";
5545
+ box.appendChild( dragIcon );
5257
5546
 
5258
- if( options.disabled ) {
5547
+ if( options.disabled )
5548
+ {
5259
5549
  vecinput.disabled = true;
5260
5550
  }
5261
5551
 
5262
5552
  // Add wheel input
5263
-
5264
5553
  vecinput.addEventListener( "wheel", function( e ) {
5265
5554
  e.preventDefault();
5266
5555
  if( this !== document.activeElement )
@@ -5269,14 +5558,17 @@ console.warn( 'Script "build/lexgui.js" is depracated and will be removed soon.
5269
5558
  if( e.shiftKey ) mult = 10;
5270
5559
  else if( e.altKey ) mult = 0.1;
5271
5560
 
5272
- if( lock_icon.locked )
5561
+ if( locker.locked )
5273
5562
  {
5274
- for( let v of element.querySelectorAll(".vecinput") ) {
5275
- v.value = ( +v.valueAsNumber - mult * ( e.deltaY > 0 ? 1 : -1 ) ).toPrecision( 5 );
5276
- Panel._dispatch_event(v, "change");
5563
+ for( let v of element.querySelectorAll(".vecinput") )
5564
+ {
5565
+ v.value = round( +v.valueAsNumber - mult * ( e.deltaY > 0 ? 1 : -1 ), options.precision );
5566
+ Panel._dispatch_event( v, "change" );
5277
5567
  }
5278
- } else {
5279
- this.value = ( +this.valueAsNumber - mult * ( e.deltaY > 0 ? 1 : -1 ) ).toPrecision( 5 );
5568
+ }
5569
+ else
5570
+ {
5571
+ this.value = round( +this.valueAsNumber - mult * ( e.deltaY > 0 ? 1 : -1 ), options.precision );
5280
5572
  Panel._dispatch_event( vecinput, "change" );
5281
5573
  }
5282
5574
  }, { passive: false } );
@@ -5289,7 +5581,7 @@ console.warn( 'Script "build/lexgui.js" is depracated and will be removed soon.
5289
5581
  const skipCallback = e.detail;
5290
5582
 
5291
5583
  let val = e.target.value = clamp( e.target.value, +vecinput.min, +vecinput.max );
5292
- val = options.precision ? round( val, options.precision ) : val;
5584
+ val = round( val, options.precision );
5293
5585
 
5294
5586
  // Reset button (default value)
5295
5587
  if( !skipCallback )
@@ -5298,13 +5590,14 @@ console.warn( 'Script "build/lexgui.js" is depracated and will be removed soon.
5298
5590
  if( btn ) btn.style.display = val != vecinput.iValue ? "block": "none";
5299
5591
  }
5300
5592
 
5301
- if( lock_icon.locked )
5593
+ if( locker.locked )
5302
5594
  {
5303
5595
  for( let v of element.querySelectorAll( ".vecinput" ) ) {
5304
5596
  v.value = val;
5305
5597
  value[ v.idx ] = val;
5306
5598
  }
5307
- } else {
5599
+ } else
5600
+ {
5308
5601
  vecinput.value = val;
5309
5602
  value[ e.target.idx ] = val;
5310
5603
  }
@@ -5318,35 +5611,48 @@ console.warn( 'Script "build/lexgui.js" is depracated and will be removed soon.
5318
5611
 
5319
5612
  var that = this;
5320
5613
  var lastY = 0;
5321
- function inner_mousedown(e) {
5322
- if(document.activeElement == vecinput) return;
5614
+ function inner_mousedown( e )
5615
+ {
5616
+ if( document.activeElement == vecinput )
5617
+ {
5618
+ return;
5619
+ }
5620
+
5323
5621
  var doc = that.root.ownerDocument;
5324
- doc.addEventListener("mousemove",inner_mousemove);
5325
- doc.addEventListener("mouseup",inner_mouseup);
5622
+ doc.addEventListener( 'mousemove', inner_mousemove );
5623
+ doc.addEventListener( 'mouseup', inner_mouseup );
5326
5624
  lastY = e.pageY;
5327
- document.body.classList.add('nocursor');
5328
- document.body.classList.add('noevents');
5329
- drag_icon.classList.remove('hidden');
5625
+ document.body.classList.add( 'nocursor' );
5626
+ document.body.classList.add( 'noevents' );
5627
+ dragIcon.classList.remove( 'hidden' );
5330
5628
  e.stopImmediatePropagation();
5331
5629
  e.stopPropagation();
5630
+
5631
+ if( options.onPress )
5632
+ {
5633
+ options.onPress.bind( vecinput )( e, vecinput );
5634
+ }
5332
5635
  }
5333
5636
 
5334
- function inner_mousemove(e) {
5335
- if (lastY != e.pageY) {
5637
+ function inner_mousemove( e )
5638
+ {
5639
+ if ( lastY != e.pageY ) {
5336
5640
  let dt = lastY - e.pageY;
5337
5641
  let mult = options.step ?? 1;
5338
- if(e.shiftKey) mult = 10;
5339
- else if(e.altKey) mult = 0.1;
5642
+ if( e.shiftKey ) mult = 10;
5643
+ else if( e.altKey ) mult = 0.1;
5340
5644
 
5341
- if( lock_icon.locked )
5645
+ if( locker.locked )
5342
5646
  {
5343
- for( let v of element.querySelectorAll(".vecinput") ) {
5344
- v.value = (+v.valueAsNumber + mult * dt).toPrecision(5);
5345
- Panel._dispatch_event(v, "change");
5647
+ for( let v of element.querySelectorAll( ".vecinput" ) ) {
5648
+ v.value = round( +v.valueAsNumber + mult * dt, options.precision );
5649
+ Panel._dispatch_event( v, "change" );
5346
5650
  }
5347
- } else {
5348
- vecinput.value = (+vecinput.valueAsNumber + mult * dt).toPrecision(5);
5349
- Panel._dispatch_event(vecinput, "change");
5651
+ }
5652
+ else
5653
+ {
5654
+ vecinput.value = round( +vecinput.valueAsNumber + mult * dt, options.precision );
5655
+ Panel._dispatch_event( vecinput, "change" );
5350
5656
  }
5351
5657
  }
5352
5658
 
@@ -5355,34 +5661,59 @@ console.warn( 'Script "build/lexgui.js" is depracated and will be removed soon.
5355
5661
  e.preventDefault();
5356
5662
  }
5357
5663
 
5358
- function inner_mouseup(e) {
5664
+ function inner_mouseup( e )
5665
+ {
5359
5666
  var doc = that.root.ownerDocument;
5360
- doc.removeEventListener("mousemove",inner_mousemove);
5361
- doc.removeEventListener("mouseup",inner_mouseup);
5362
- document.body.classList.remove('nocursor');
5363
- document.body.classList.remove('noevents');
5364
- drag_icon.classList.add('hidden');
5667
+ doc.removeEventListener( 'mousemove', inner_mousemove );
5668
+ doc.removeEventListener( 'mouseup', inner_mouseup );
5669
+ document.body.classList.remove( 'nocursor' );
5670
+ document.body.classList.remove( 'noevents' );
5671
+ dragIcon.classList.add('hidden');
5672
+
5673
+ if( options.onRelease )
5674
+ {
5675
+ options.onRelease.bind( vecinput )( e, vecinput );
5676
+ }
5365
5677
  }
5366
-
5367
- box.appendChild(vecinput);
5368
- container.appendChild(box);
5678
+
5679
+ box.appendChild( vecinput );
5680
+ container.appendChild( box );
5369
5681
  }
5370
5682
 
5371
- let lock_icon = document.createElement('a');
5372
- lock_icon.className = "fa-solid fa-lock-open lexicon";
5373
- container.appendChild(lock_icon);
5374
- lock_icon.addEventListener("click", function(e) {
5683
+ // Method to change min, max, step parameters
5684
+ if( options.min !== undefined || options.max !== undefined )
5685
+ {
5686
+ widget.setLimits = ( newMin, newMax, newStep ) => {
5687
+ const inputs = element.querySelectorAll(".vecinput");
5688
+ for( let v of inputs )
5689
+ {
5690
+ v.min = newMin ?? v.min;
5691
+ v.max = newMax ?? v.max;
5692
+ v.step = newStep ?? v.step;
5693
+ Panel._dispatch_event( v, "change", true );
5694
+ }
5695
+
5696
+ // To call onChange callback
5697
+ this._trigger( new IEvent( name, value ), callback );
5698
+ };
5699
+ }
5700
+
5701
+ let locker = document.createElement( 'a' );
5702
+ locker.className = "fa-solid fa-lock-open lexicon";
5703
+ container.appendChild( locker );
5704
+ locker.addEventListener( "click", function( e ) {
5375
5705
  this.locked = !this.locked;
5376
- if(this.locked){
5377
- this.classList.add("fa-lock");
5378
- this.classList.remove("fa-lock-open");
5706
+ if( this.locked )
5707
+ {
5708
+ this.classList.add( "fa-lock" );
5709
+ this.classList.remove( "fa-lock-open" );
5379
5710
  } else {
5380
- this.classList.add("fa-lock-open");
5381
- this.classList.remove("fa-lock");
5711
+ this.classList.add( "fa-lock-open" );
5712
+ this.classList.remove( "fa-lock" );
5382
5713
  }
5383
- }, false);
5714
+ }, false );
5384
5715
 
5385
- element.appendChild(container);
5716
+ element.appendChild( container );
5386
5717
 
5387
5718
  return widget;
5388
5719
  }
@@ -5396,21 +5727,231 @@ console.warn( 'Script "build/lexgui.js" is depracated and will be removed soon.
5396
5727
  * disabled: Make the widget disabled [false]
5397
5728
  * step: Step of the inputs
5398
5729
  * min, max: Min and Max values for the inputs
5730
+ * onPress: Callback function on mouse down
5731
+ * onRelease: Callback function on mouse up
5399
5732
  */
5400
5733
 
5401
5734
  addVector2( name, value, callback, options ) {
5402
5735
 
5403
- return this._add_vector(2, name, value, callback, options);
5736
+ return this._add_vector( 2, name, value, callback, options );
5404
5737
  }
5405
5738
 
5406
5739
  addVector3( name, value, callback, options ) {
5407
5740
 
5408
- return this._add_vector(3, name, value, callback, options);
5741
+ return this._add_vector( 3, name, value, callback, options );
5409
5742
  }
5410
5743
 
5411
5744
  addVector4( name, value, callback, options ) {
5412
5745
 
5413
- return this._add_vector(4, name, value, callback, options);
5746
+ return this._add_vector( 4, name, value, callback, options );
5747
+ }
5748
+
5749
+ /**
5750
+ * @method addSize
5751
+ * @param {String} name Widget name
5752
+ * @param {Number} value Default number value
5753
+ * @param {Function} callback Callback function on change
5754
+ * @param {*} options:
5755
+ * disabled: Make the widget disabled [false]
5756
+ * units: Unit as string added to the end of the value
5757
+ */
5758
+
5759
+ addSize( name, value, callback, options = {} ) {
5760
+
5761
+ let widget = this.create_widget( name, Widget.SIZE, options );
5762
+
5763
+ widget.onGetValue = () => {
5764
+ const value = [];
5765
+ for( let i = 0; i < element.dimensions.length; ++i )
5766
+ {
5767
+ value.push( element.dimensions[ i ].onGetValue() );
5768
+ }
5769
+ return value;
5770
+ };
5771
+
5772
+ widget.onSetValue = ( newValue, skipCallback ) => {
5773
+ for( let i = 0; i < element.dimensions.length; ++i )
5774
+ {
5775
+ element.dimensions[ i ].onSetValue( newValue[ i ], skipCallback );
5776
+ }
5777
+ };
5778
+
5779
+ let element = widget.domEl;
5780
+
5781
+ this.queue( element );
5782
+
5783
+ element.dimensions = [];
5784
+
5785
+ for( let i = 0; i < value.length; ++i )
5786
+ {
5787
+ const size = measureRealWidth( JSON.stringify( value[ i ] ), 24 ) + 'px';
5788
+ element.dimensions[ i ] = this.addNumber( null, value[ i ], ( v ) => {
5789
+
5790
+ const value = [];
5791
+
5792
+ for( let i = 0; i < element.dimensions.length; ++i )
5793
+ {
5794
+ value.push( element.dimensions[ i ].onGetValue() );
5795
+ }
5796
+
5797
+ if( callback )
5798
+ {
5799
+ callback( value );
5800
+ }
5801
+
5802
+ }, { width: size, min: 0, disabled: options.disabled } );
5803
+
5804
+ if( ( i + 1 ) != value.length )
5805
+ {
5806
+ let cross = document.createElement( 'a' );
5807
+ cross.className = "lexsizecross fa-solid fa-xmark";
5808
+ element.appendChild( cross );
5809
+ }
5810
+ }
5811
+
5812
+ this.clearQueue();
5813
+
5814
+ if( options.units )
5815
+ {
5816
+ let unitSpan = document.createElement( 'span' );
5817
+ unitSpan.className = "lexunit";
5818
+ unitSpan.innerText = options.units;
5819
+ element.appendChild( unitSpan );
5820
+ }
5821
+
5822
+ // Remove branch padding and margins
5823
+ if( !widget.name )
5824
+ {
5825
+ element.className += " noname";
5826
+ container.style.width = "100%";
5827
+ }
5828
+
5829
+ return widget;
5830
+ }
5831
+
5832
+ /**
5833
+ * @method addPad
5834
+ * @param {String} name Widget name
5835
+ * @param {Number} value Pad value
5836
+ * @param {Function} callback Callback function on change
5837
+ * @param {*} options:
5838
+ * disabled: Make the widget disabled [false]
5839
+ * min, max: Min and Max values
5840
+ * onPress: Callback function on mouse down
5841
+ * onRelease: Callback function on mouse up
5842
+ */
5843
+
5844
+ addPad( name, value, callback, options = {} ) {
5845
+
5846
+ if( !name )
5847
+ {
5848
+ throw( "Set Widget Name!" );
5849
+ }
5850
+
5851
+ let widget = this.create_widget( name, Widget.PAD, options );
5852
+
5853
+ widget.onGetValue = () => {
5854
+ return thumb.value.xy;
5855
+ };
5856
+
5857
+ widget.onSetValue = ( newValue, skipCallback ) => {
5858
+ thumb.value.set( newValue[ 0 ], newValue[ 1 ] );
5859
+ _updateValue( thumb.value );
5860
+ if( !skipCallback )
5861
+ {
5862
+ this._trigger( new IEvent( name, thumb.value.xy ), callback );
5863
+ }
5864
+ };
5865
+
5866
+ let element = widget.domEl;
5867
+
5868
+ var container = document.createElement( 'div' );
5869
+ container.className = "lexpad";
5870
+ container.style.width = "calc( 100% - " + LX.DEFAULT_NAME_WIDTH + ")";
5871
+
5872
+ let pad = document.createElement('div');
5873
+ pad.id = "lexpad-" + name;
5874
+ pad.className = "lexinnerpad";
5875
+ pad.style.width = options.padSize ?? '96px';
5876
+ pad.style.height = options.padSize ?? '96px';
5877
+
5878
+ let thumb = document.createElement('div');
5879
+ thumb.className = "lexpadthumb";
5880
+ thumb.value = new LX.vec2( value[ 0 ], value[ 1 ] );
5881
+ thumb.min = options.min ?? 0;
5882
+ thumb.max = options.max ?? 1;
5883
+
5884
+ let _updateValue = v => {
5885
+ const [ w, h ] = [ pad.offsetWidth, pad.offsetHeight ];
5886
+ const value0to1 = new LX.vec2( remapRange( v.x, thumb.min, thumb.max, 0.0, 1.0 ), remapRange( v.y, thumb.min, thumb.max, 0.0, 1.0 ) );
5887
+ thumb.style.transform = `translate(calc( ${ w * value0to1.x }px - 50% ), calc( ${ h * value0to1.y }px - 50%)`;
5888
+ }
5889
+
5890
+ doAsync( () => {
5891
+ _updateValue( thumb.value )
5892
+ } );
5893
+
5894
+ pad.appendChild( thumb );
5895
+ container.appendChild( pad );
5896
+ element.appendChild( container );
5897
+
5898
+ pad.addEventListener( "mousedown", innerMouseDown );
5899
+
5900
+ let that = this;
5901
+
5902
+ function innerMouseDown( e )
5903
+ {
5904
+ if( document.activeElement == thumb )
5905
+ {
5906
+ return;
5907
+ }
5908
+
5909
+ var doc = that.root.ownerDocument;
5910
+ doc.addEventListener( 'mousemove', innerMouseMove );
5911
+ doc.addEventListener( 'mouseup', innerMouseUp );
5912
+ document.body.classList.add( 'nocursor' );
5913
+ document.body.classList.add( 'noevents' );
5914
+ e.stopImmediatePropagation();
5915
+ e.stopPropagation();
5916
+
5917
+ if( options.onPress )
5918
+ {
5919
+ options.onPress.bind( thumb )( e, thumb );
5920
+ }
5921
+ }
5922
+
5923
+ function innerMouseMove( e )
5924
+ {
5925
+ const rect = pad.getBoundingClientRect();
5926
+ const relativePosition = new LX.vec2( e.x - rect.x, e.y - rect.y );
5927
+ relativePosition.clp( 0.0, pad.offsetWidth, relativePosition);
5928
+ const [ w, h ] = [ pad.offsetWidth, pad.offsetHeight ];
5929
+ const value0to1 = relativePosition.div( new LX.vec2( pad.offsetWidth, pad.offsetHeight ) );
5930
+
5931
+ thumb.style.transform = `translate(calc( ${ w * value0to1.x }px - 50% ), calc( ${ h * value0to1.y }px - 50%)`;
5932
+ thumb.value = new LX.vec2( remapRange( value0to1.x, 0.0, 1.0, thumb.min, thumb.max ), remapRange( value0to1.y, 0.0, 1.0, thumb.min, thumb.max ) );
5933
+
5934
+ that._trigger( new IEvent( name, thumb.value.xy, e ), callback );
5935
+
5936
+ e.stopPropagation();
5937
+ e.preventDefault();
5938
+ }
5939
+
5940
+ function innerMouseUp( e )
5941
+ {
5942
+ var doc = that.root.ownerDocument;
5943
+ doc.removeEventListener( 'mousemove', innerMouseMove );
5944
+ doc.removeEventListener( 'mouseup', innerMouseUp );
5945
+ document.body.classList.remove( 'nocursor' );
5946
+ document.body.classList.remove( 'noevents' );
5947
+
5948
+ if( options.onRelease )
5949
+ {
5950
+ options.onRelease.bind( thumb )( e, thumb );
5951
+ }
5952
+ }
5953
+
5954
+ return widget;
5414
5955
  }
5415
5956
 
5416
5957
  /**
@@ -5911,8 +6452,7 @@ console.warn( 'Script "build/lexgui.js" is depracated and will be removed soon.
5911
6452
 
5912
6453
  this.grabber = grabber;
5913
6454
 
5914
- function getBranchHeight(){
5915
-
6455
+ function getBranchHeight() {
5916
6456
  return that.root.offsetHeight - that.root.children[0].offsetHeight;
5917
6457
  }
5918
6458
 
@@ -5966,20 +6506,23 @@ console.warn( 'Script "build/lexgui.js" is depracated and will be removed soon.
5966
6506
  var size = this.grabber.style.marginLeft;
5967
6507
 
5968
6508
  // Update sizes of widgets inside
5969
- for(var i = 0; i < this.widgets.length;i++) {
6509
+ for(var i = 0; i < this.widgets.length; i++) {
5970
6510
 
5971
- let widget = this.widgets[i];
6511
+ let widget = this.widgets[ i ];
5972
6512
  let element = widget.domEl;
5973
6513
 
5974
- if(element.children.length < 2)
6514
+ if( element.children.length < 2 )
6515
+ {
5975
6516
  continue;
6517
+ }
5976
6518
 
5977
- var name = element.children[0];
5978
- var value = element.children[1];
6519
+ var name = element.children[ 0 ];
6520
+ var value = element.children[ 1 ];
5979
6521
 
5980
6522
  name.style.width = size;
5981
6523
  let padding = "0px";
5982
- switch(widget.type) {
6524
+ switch( widget.type )
6525
+ {
5983
6526
  case Widget.FILE:
5984
6527
  padding = "10%";
5985
6528
  break;
@@ -5992,7 +6535,10 @@ console.warn( 'Script "build/lexgui.js" is depracated and will be removed soon.
5992
6535
  value.style.width = "-webkit-calc( 100% - " + size + " - " + padding + " )";
5993
6536
  value.style.width = "calc( 100% - " + size + " - " + padding + " )";
5994
6537
 
5995
- if(widget.onresize) widget.onresize();
6538
+ if( widget.onresize )
6539
+ {
6540
+ widget.onresize();
6541
+ }
5996
6542
  }
5997
6543
  }
5998
6544
  };
@@ -6009,8 +6555,10 @@ console.warn( 'Script "build/lexgui.js" is depracated and will be removed soon.
6009
6555
 
6010
6556
  constructor( title, callback, options = {} ) {
6011
6557
 
6012
- if(!callback)
6013
- console.warn("Content is empty, add some widgets using 'callback' parameter!");
6558
+ if( !callback )
6559
+ {
6560
+ console.warn("Content is empty, add some widgets using 'callback' parameter!");
6561
+ }
6014
6562
 
6015
6563
  this._oncreate = callback;
6016
6564
  this.id = simple_guidGenerator();
@@ -6020,8 +6568,10 @@ console.warn( 'Script "build/lexgui.js" is depracated and will be removed soon.
6020
6568
  draggable = options.draggable ?? true,
6021
6569
  modal = options.modal ?? false;
6022
6570
 
6023
- if(modal)
6024
- LX.modal.toggle(false);
6571
+ if( modal )
6572
+ {
6573
+ LX.modal.toggle( false );
6574
+ }
6025
6575
 
6026
6576
  var root = document.createElement('div');
6027
6577
  root.className = "lexdialog " + (options.class ?? "");
@@ -6032,8 +6582,8 @@ console.warn( 'Script "build/lexgui.js" is depracated and will be removed soon.
6032
6582
 
6033
6583
  var titleDiv = document.createElement('div');
6034
6584
 
6035
- if(title) {
6036
-
6585
+ if( title )
6586
+ {
6037
6587
  titleDiv.className = "lexdialogtitle";
6038
6588
  titleDiv.innerHTML = title;
6039
6589
  titleDiv.setAttribute('draggable', false);
@@ -6137,7 +6687,9 @@ console.warn( 'Script "build/lexgui.js" is depracated and will be removed soon.
6137
6687
  this.title = titleDiv;
6138
6688
 
6139
6689
  if( draggable )
6140
- makeDraggable( root, { targetClass: 'lexdialogtitle' } );
6690
+ {
6691
+ makeDraggable( root, Object.assign( { targetClass: 'lexdialogtitle' }, options ) );
6692
+ }
6141
6693
 
6142
6694
  // Process position and size
6143
6695
  if(size.length && typeof(size[0]) != "string")
@@ -6302,7 +6854,8 @@ console.warn( 'Script "build/lexgui.js" is depracated and will be removed soon.
6302
6854
  this.items = [];
6303
6855
  this.colors = {};
6304
6856
 
6305
- if(title) {
6857
+ if( title )
6858
+ {
6306
6859
  const item = {};
6307
6860
  item[ title ] = [];
6308
6861
  item[ 'className' ] = "cmtitle";
@@ -6311,28 +6864,42 @@ console.warn( 'Script "build/lexgui.js" is depracated and will be removed soon.
6311
6864
  }
6312
6865
  }
6313
6866
 
6314
- _adjust_position(div, margin, useAbsolute = false) {
6315
-
6867
+ _adjust_position( div, margin, useAbsolute = false ) {
6868
+
6316
6869
  let rect = div.getBoundingClientRect();
6317
6870
 
6318
- if(!useAbsolute)
6871
+ if( !useAbsolute )
6319
6872
  {
6320
- let width = rect.width + 36; // this has paddings
6321
- if(window.innerWidth - rect.right < 0)
6873
+ let width = rect.width;
6874
+ if( rect.left < 0 )
6875
+ {
6876
+ div.style.left = margin + "px";
6877
+ }
6878
+ else if( window.innerWidth - rect.right < 0 )
6879
+ {
6322
6880
  div.style.left = (window.innerWidth - width - margin) + "px";
6881
+ }
6323
6882
 
6324
- if(rect.top + rect.height > window.innerHeight)
6883
+ if( rect.top < 0 )
6884
+ {
6885
+ div.style.top = margin + "px";
6886
+ }
6887
+ else if( (rect.top + rect.height) > window.innerHeight )
6888
+ {
6325
6889
  div.style.top = (window.innerHeight - rect.height - margin) + "px";
6890
+ }
6326
6891
  }
6327
6892
  else
6328
6893
  {
6329
6894
  let dt = window.innerWidth - rect.right;
6330
- if(dt < 0) {
6895
+ if( dt < 0 )
6896
+ {
6331
6897
  div.style.left = div.offsetLeft + (dt - margin) + "px";
6332
6898
  }
6333
6899
 
6334
6900
  dt = window.innerHeight - (rect.top + rect.height);
6335
- if(dt < 0) {
6901
+ if( dt < 0 )
6902
+ {
6336
6903
  div.style.top = div.offsetTop + (dt - margin + 20 ) + "px";
6337
6904
  }
6338
6905
  }
@@ -6358,7 +6925,6 @@ console.warn( 'Script "build/lexgui.js" is depracated and will be removed soon.
6358
6925
  contextmenu.style.marginTop = 3.5 - c.offsetHeight + "px";
6359
6926
 
6360
6927
  // Set final width
6361
- // contextmenu.style.width = contextmenu.offsetWidth + "px";
6362
6928
  this._adjust_position( contextmenu, 6, true );
6363
6929
  }
6364
6930
 
@@ -6432,7 +6998,7 @@ console.warn( 'Script "build/lexgui.js" is depracated and will be removed soon.
6432
6998
  }
6433
6999
 
6434
7000
  onCreate() {
6435
- this._adjust_position( this.root, 6 );
7001
+ doAsync( () => this._adjust_position( this.root, 6 ) );
6436
7002
  }
6437
7003
 
6438
7004
  add( path, options = {} ) {
@@ -6537,10 +7103,12 @@ console.warn( 'Script "build/lexgui.js" is depracated and will be removed soon.
6537
7103
  function addContextMenu( title, event, callback, options )
6538
7104
  {
6539
7105
  var menu = new ContextMenu( event, title, options );
6540
- LX.root.appendChild(menu.root);
7106
+ LX.root.appendChild( menu.root );
6541
7107
 
6542
- if(callback)
7108
+ if( callback )
7109
+ {
6543
7110
  callback( menu );
7111
+ }
6544
7112
 
6545
7113
  menu.onCreate();
6546
7114