lexgui 0.1.37 → 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.
@@ -8,7 +8,7 @@
8
8
  */
9
9
 
10
10
  var LX = {
11
- version: "0.1.37",
11
+ version: "0.1.39",
12
12
  ready: false,
13
13
  components: [], // specific pre-build components
14
14
  signals: {} // events and triggers
@@ -26,9 +26,11 @@ LX.CURVE_MOVEOUT_DELETE = 1;
26
26
 
27
27
  function clamp( num, min, max ) { return Math.min( Math.max( num, min ), max ); }
28
28
  function round( number, precision ) { return +(( number ).toFixed( precision ?? 2 ).replace( /([0-9]+(\.[0-9]+[1-9])?)(\.?0+$)/, '$1' )); }
29
+ function remapRange( oldValue, oldMin, oldMax, newMin, newMax ) { return ((( oldValue - oldMin ) * ( newMax - newMin )) / ( oldMax - oldMin )) + newMin; }
29
30
 
30
31
  LX.clamp = clamp;
31
32
  LX.round = round;
33
+ LX.remapRange = remapRange;
32
34
 
33
35
  function getSupportedDOMName( string )
34
36
  {
@@ -105,6 +107,18 @@ function rgbToHex( rgb ) {
105
107
 
106
108
  LX.rgbToHex = rgbToHex;
107
109
 
110
+ function measureRealWidth( value, paddingPlusMargin = 8 ) {
111
+ var i = document.createElement( "span" );
112
+ i.className = "lexinputmeasure";
113
+ i.innerHTML = value;
114
+ document.body.appendChild( i );
115
+ var rect = i.getBoundingClientRect();
116
+ LX.UTILS.deleteElement( i );
117
+ return rect.width + paddingPlusMargin;
118
+ }
119
+
120
+ LX.measureRealWidth = measureRealWidth;
121
+
108
122
  function simple_guidGenerator() {
109
123
  var S4 = function() {
110
124
  return (((1+Math.random())*0x10000)|0).toString(16).substring(1);
@@ -166,36 +180,69 @@ class vec2 {
166
180
  len () { return Math.sqrt( this.len2() ); }
167
181
  nrm ( v0 = new vec2() ) { v0.set( this.x, this.y ); return v0.mul( 1.0 / this.len(), v0 ); }
168
182
  dst ( v ) { return v.sub( this ).len(); }
183
+ clp ( min, max, v0 = new vec2() ) { v0.set( clamp( this.x, min, max ), clamp( this.y, min, max ) ); return v0; }
169
184
  };
170
185
 
171
186
  LX.vec2 = vec2;
172
187
 
173
188
  // Other utils
174
189
 
190
+ /**
191
+ * @method makeDraggable
192
+ * @param {Element} domEl
193
+ * @param {Object} options
194
+ * autoAdjust (Bool): Sets in a correct position at the beggining
195
+ * dragMargin (Number): Margin of drag container
196
+ * onMove (Function): Called each move event
197
+ * onDragStart (Function): Called when drag event starts
198
+ */
175
199
  function makeDraggable( domEl, options = { } ) {
176
200
 
177
- let offsetX;
178
- let offsetY;
201
+ let offsetX = 0;
202
+ let offsetY = 0;
179
203
  let currentTarget = null;
180
204
  let targetClass = options.targetClass;
205
+ let dragMargin = options.dragMargin ?? 3;
206
+
207
+ let _computePosition = ( e, top, left ) => {
208
+ const nullRect = { x: 0, y: 0, width: 0, height: 0 };
209
+ const parentRect = domEl.parentElement ? domEl.parentElement.getBoundingClientRect() : nullRect;
210
+ const isFixed = ( domEl.style.position == "fixed" );
211
+ const fixedOffset = isFixed ? new LX.vec2( parentRect.x, parentRect.y ) : new LX.vec2();
212
+ left = left ?? e.clientX - offsetX - parentRect.x;
213
+ top = top ?? e.clientY - offsetY - parentRect.y;
214
+ domEl.style.left = clamp( left, dragMargin + fixedOffset.x, fixedOffset.x + parentRect.width - domEl.offsetWidth - dragMargin ) + 'px';
215
+ domEl.style.top = clamp( top, dragMargin + fixedOffset.y, fixedOffset.y + parentRect.height - domEl.offsetHeight - dragMargin ) + 'px';
216
+ };
217
+
218
+ // Initial adjustment
219
+ if( options.autoAdjust )
220
+ {
221
+ _computePosition( null, parseInt( domEl.style.left ), parseInt( domEl.style.top ) )
222
+ }
181
223
 
182
224
  let id = LX.UTILS.uidGenerator();
183
225
  domEl[ 'draggable-id' ] = id;
184
226
 
185
227
  const defaultMoveFunc = e => {
186
- if( !currentTarget ) return;
187
- let left = e.clientX - offsetX;
188
- let top = e.clientY - offsetY;
189
- if( left > 3 && ( left + domEl.offsetWidth + 6 ) <= window.innerWidth )
190
- domEl.style.left = left + 'px';
191
- if( top > 3 && ( top + domEl.offsetHeight + 6 ) <= window.innerHeight )
192
- domEl.style.top = top + 'px';
228
+ if( !currentTarget )
229
+ {
230
+ return;
231
+ }
232
+
233
+ _computePosition( e );
193
234
  };
194
235
 
195
236
  const customMoveFunc = e => {
196
- if( !currentTarget ) return;
237
+ if( !currentTarget )
238
+ {
239
+ return;
240
+ }
241
+
197
242
  if( options.onMove )
243
+ {
198
244
  options.onMove( currentTarget );
245
+ }
199
246
  };
200
247
 
201
248
  let onMove = options.onMove ? customMoveFunc : defaultMoveFunc;
@@ -203,7 +250,7 @@ function makeDraggable( domEl, options = { } ) {
203
250
 
204
251
  domEl.setAttribute( 'draggable', true );
205
252
  domEl.addEventListener( "mousedown", function( e ) {
206
- currentTarget = (e.target.classList.contains(targetClass) || !targetClass) ? e.target : null;
253
+ currentTarget = ( e.target.classList.contains( targetClass ) || !targetClass ) ? e.target : null;
207
254
  } );
208
255
 
209
256
  domEl.addEventListener( "dragstart", function( e ) {
@@ -217,15 +264,21 @@ function makeDraggable( domEl, options = { } ) {
217
264
  e.dataTransfer.setDragImage( img, 0, 0 );
218
265
  e.dataTransfer.effectAllowed = "move";
219
266
  const rect = e.target.getBoundingClientRect();
220
- offsetX = e.clientX - rect.x;
221
- offsetY = e.clientY - rect.y;
267
+ const parentRect = currentTarget.parentElement.getBoundingClientRect();
268
+ const isFixed = ( currentTarget.style.position == "fixed" );
269
+ const fixedOffset = isFixed ? new LX.vec2( parentRect.x, parentRect.y ) : new LX.vec2();
270
+ offsetX = e.clientX - rect.x - fixedOffset.x;
271
+ offsetY = e.clientY - rect.y - fixedOffset.y;
222
272
  document.addEventListener( "mousemove", onMove );
223
273
  if( onDragStart )
274
+ {
224
275
  onDragStart( currentTarget, e );
276
+ }
225
277
  }, false );
226
278
 
227
279
  document.addEventListener( 'mouseup', () => {
228
- if( currentTarget ) {
280
+ if( currentTarget )
281
+ {
229
282
  currentTarget = null;
230
283
  document.removeEventListener( "mousemove", onMove );
231
284
  }
@@ -666,7 +719,8 @@ class TreeEvent {
666
719
  }
667
720
 
668
721
  string() {
669
- switch(this.type) {
722
+ switch( this.type )
723
+ {
670
724
  case TreeEvent.NONE: return "tree_event_none";
671
725
  case TreeEvent.NODE_SELECTED: return "tree_event_selected";
672
726
  case TreeEvent.NODE_DELETED: return "tree_event_deleted";
@@ -820,7 +874,9 @@ class Area {
820
874
 
821
875
  const draggable = options.draggable ?? true;
822
876
  if( draggable )
823
- makeDraggable( root );
877
+ {
878
+ makeDraggable( root, options );
879
+ }
824
880
 
825
881
  if( options.resizeable ) {
826
882
  root.classList.add("resizeable");
@@ -1182,23 +1238,33 @@ class Area {
1182
1238
  * @method resize
1183
1239
  * Resize element
1184
1240
  */
1185
- setSize(size) {
1241
+ setSize( size ) {
1186
1242
 
1187
- let [width, height] = size;
1243
+ let [ width, height ] = size;
1188
1244
 
1189
- if(width != undefined && width.constructor == Number)
1245
+ if( width != undefined && width.constructor == Number )
1246
+ {
1190
1247
  width += "px";
1191
- if(height != undefined && height.constructor == Number)
1248
+ }
1249
+
1250
+ if( height != undefined && height.constructor == Number )
1251
+ {
1192
1252
  height += "px";
1253
+ }
1193
1254
 
1194
- if(width)
1255
+ if( width )
1256
+ {
1195
1257
  this.root.style.width = width;
1196
- if(height)
1258
+ }
1259
+
1260
+ if( height )
1261
+ {
1197
1262
  this.root.style.height = height;
1263
+ }
1198
1264
 
1199
- this.size = [this.root.clientWidth, this.root.clientHeight];
1265
+ this.size = [ this.root.clientWidth, this.root.clientHeight ];
1200
1266
 
1201
- this.propagateEvent("onresize");
1267
+ this.propagateEvent( "onresize" );
1202
1268
  }
1203
1269
 
1204
1270
  /**
@@ -1208,7 +1274,9 @@ class Area {
1208
1274
  extend() {
1209
1275
 
1210
1276
  if( this.split_extended )
1211
- return;
1277
+ {
1278
+ return;
1279
+ }
1212
1280
 
1213
1281
  let [area1, area2] = this.sections;
1214
1282
  this.split_extended = true;
@@ -1877,11 +1945,15 @@ class Tabs {
1877
1945
 
1878
1946
  const tabEl = this.tabDOMs[ name ];
1879
1947
 
1880
- if(!tabEl || tabEl.fixed)
1881
- return;
1948
+ if( !tabEl || tabEl.fixed )
1949
+ {
1950
+ return;
1951
+ }
1882
1952
 
1883
1953
  if( this.onclose )
1954
+ {
1884
1955
  this.onclose( name );
1956
+ }
1885
1957
 
1886
1958
  // Delete tab element
1887
1959
  this.tabDOMs[ name ].remove();
@@ -1892,11 +1964,12 @@ class Tabs {
1892
1964
  delete this.tabs[ name ];
1893
1965
 
1894
1966
  // Select last tab
1895
- const last_tab = this.root.lastChild;
1896
- if(last_tab && !last_tab.fixed)
1967
+ const lastTab = this.root.lastChild;
1968
+ if( lastTab && !lastTab.fixed )
1969
+ {
1897
1970
  this.root.lastChild.click();
1971
+ }
1898
1972
  }
1899
-
1900
1973
  }
1901
1974
 
1902
1975
  LX.Tabs = Tabs;
@@ -2463,6 +2536,8 @@ class Widget {
2463
2536
  static CUSTOM = 21;
2464
2537
  static SEPARATOR = 22;
2465
2538
  static KNOB = 23;
2539
+ static SIZE = 24;
2540
+ static PAD = 25;
2466
2541
 
2467
2542
  static NO_CONTEXT_TYPES = [
2468
2543
  Widget.BUTTON,
@@ -2520,14 +2595,16 @@ class Widget {
2520
2595
 
2521
2596
  paste() {
2522
2597
  if( !this._can_paste() )
2523
- return;
2598
+ {
2599
+ return;
2600
+ }
2524
2601
 
2525
- this.set(navigator.clipboard.data);
2602
+ this.set( navigator.clipboard.data );
2526
2603
  }
2527
2604
 
2528
2605
  typeName() {
2529
2606
 
2530
- switch(this.type) {
2607
+ switch( this.type ) {
2531
2608
  case Widget.TEXT: return "Text";
2532
2609
  case Widget.TEXTAREA: return "TextArea";
2533
2610
  case Widget.BUTTON: return "Button";
@@ -2545,6 +2622,8 @@ class Widget {
2545
2622
  case Widget.TAGS: return "Tags";
2546
2623
  case Widget.CURVE: return "Curve";
2547
2624
  case Widget.KNOB: return "Knob";
2625
+ case Widget.SIZE: return "Size";
2626
+ case Widget.PAD: return "Pad";
2548
2627
  case Widget.CUSTOM: return this.customName;
2549
2628
  }
2550
2629
  }
@@ -2639,40 +2718,50 @@ function ADD_CUSTOM_WIDGET( custom_widget_name, options = {} )
2639
2718
  custom_widgets.className = "lexcustomitems";
2640
2719
  custom_widgets.toggleAttribute('hidden', true);
2641
2720
 
2642
- element.appendChild(container);
2643
- element.appendChild(custom_widgets);
2721
+ element.appendChild( container );
2722
+ element.appendChild( custom_widgets );
2723
+
2724
+ if( instance )
2725
+ {
2644
2726
 
2645
- if( instance ) {
2646
-
2647
2727
  this.queue( custom_widgets );
2648
2728
 
2649
- const on_instance_changed = (key, value, event) => {
2650
- instance[key] = value;
2651
- this._trigger( new IEvent(name, instance, event), callback );
2729
+ const on_instance_changed = ( key, value, event ) => {
2730
+ instance[ key ] = value;
2731
+ this._trigger( new IEvent( name, instance, event ), callback );
2652
2732
  };
2653
2733
 
2654
2734
  for( let key in default_instance )
2655
2735
  {
2656
- const value = instance[key] ?? default_instance[key];
2736
+ const value = instance[ key ] ?? default_instance[ key ];
2657
2737
 
2658
- switch(value.constructor) {
2738
+ switch( value.constructor )
2739
+ {
2659
2740
  case String:
2660
- if(value[0] === '#')
2661
- this.addColor(key, value, on_instance_changed.bind(this, key));
2741
+ if( value[ 0 ] === '#' )
2742
+ {
2743
+ this.addColor( key, value, on_instance_changed.bind( this, key ) );
2744
+ }
2662
2745
  else
2663
- this.addText(key, value, on_instance_changed.bind(this, key));
2746
+ {
2747
+ this.addText( key, value, on_instance_changed.bind( this, key ) );
2748
+ }
2664
2749
  break;
2665
2750
  case Number:
2666
- this.addNumber(key, value, on_instance_changed.bind(this, key));
2751
+ this.addNumber( key, value, on_instance_changed.bind( this, key ) );
2667
2752
  break;
2668
2753
  case Boolean:
2669
- this.addCheckbox(key, value, on_instance_changed.bind(this, key));
2754
+ this.addCheckbox( key, value, on_instance_changed.bind( this, key ) );
2670
2755
  break;
2671
2756
  case Array:
2672
2757
  if( value.length > 4 )
2673
- this.addArray(key, value, on_instance_changed.bind(this, key));
2758
+ {
2759
+ this.addArray( key, value, on_instance_changed.bind( this, key ) );
2760
+ }
2674
2761
  else
2675
- this._add_vector(value.length, key, value, on_instance_changed.bind(this, key));
2762
+ {
2763
+ this._add_vector( value.length, key, value, on_instance_changed.bind( this, key ) );
2764
+ }
2676
2765
  break;
2677
2766
  }
2678
2767
  }
@@ -2711,37 +2800,40 @@ class NodeTree {
2711
2800
  _create_item( parent, node, level = 0, selectedId ) {
2712
2801
 
2713
2802
  const that = this;
2714
- const node_filter_input = this.domEl.querySelector("#lexnodetree_filter");
2803
+ const node_filter_input = this.domEl.querySelector( "#lexnodetree_filter" );
2715
2804
 
2716
2805
  node.children = node.children ?? [];
2717
- if(node_filter_input && !node.id.includes(node_filter_input.value) || (selectedId != undefined) && selectedId != node.id)
2806
+ if( node_filter_input && !node.id.includes( node_filter_input.value ) || (selectedId != undefined) && selectedId != node.id )
2718
2807
  {
2719
2808
  for( var i = 0; i < node.children.length; ++i )
2720
- this._create_item( node, node.children[i], level + 1, selectedId );
2809
+ {
2810
+ this._create_item( node, node.children[ i ], level + 1, selectedId );
2811
+ }
2721
2812
  return;
2722
2813
  }
2723
2814
 
2724
- const list = this.domEl.querySelector("ul");
2815
+ const list = this.domEl.querySelector( 'ul' );
2725
2816
 
2726
2817
  node.visible = node.visible ?? true;
2727
2818
  node.parent = parent;
2728
- let is_parent = node.children.length > 0;
2729
- let is_selected = this.selected.indexOf( node ) > -1 || node.selected;
2819
+ let isParent = node.children.length > 0;
2820
+ let isSelected = this.selected.indexOf( node ) > -1 || node.selected;
2730
2821
 
2731
- if( this.options.only_folders ) {
2822
+ if( this.options.only_folders )
2823
+ {
2732
2824
  let has_folders = false;
2733
2825
  node.children.forEach( c => has_folders |= (c.type == 'folder') );
2734
- is_parent = !!has_folders;
2826
+ isParent = !!has_folders;
2735
2827
  }
2736
2828
 
2737
2829
  let item = document.createElement('li');
2738
- item.className = "lextreeitem " + "datalevel" + level + (is_parent ? " parent" : "") + (is_selected ? " selected" : "");
2830
+ item.className = "lextreeitem " + "datalevel" + level + (isParent ? " parent" : "") + (isSelected ? " selected" : "");
2739
2831
  item.id = LX.getSupportedDOMName( node.id );
2740
2832
  item.tabIndex = "0";
2741
2833
 
2742
2834
  // Select hierarchy icon
2743
2835
  let icon = (this.options.skip_default_icon ?? true) ? "" : "fa-solid fa-square"; // Default: no childs
2744
- if( is_parent ) icon = node.closed ? "fa-solid fa-caret-right" : "fa-solid fa-caret-down";
2836
+ if( isParent ) icon = node.closed ? "fa-solid fa-caret-right" : "fa-solid fa-caret-down";
2745
2837
  item.innerHTML = "<a class='" + icon + " hierarchy'></a>";
2746
2838
 
2747
2839
  // Add display icon
@@ -2761,18 +2853,20 @@ class NodeTree {
2761
2853
 
2762
2854
  item.innerHTML += (node.rename ? "" : node.id);
2763
2855
 
2764
- item.setAttribute('draggable', true);
2765
- item.style.paddingLeft = ((is_parent ? 0 : 3 ) + (3 + (level+1) * 15)) + "px";
2766
- list.appendChild(item);
2856
+ item.setAttribute( 'draggable', true );
2857
+ item.style.paddingLeft = ((isParent ? 0 : 3 ) + (3 + (level+1) * 15)) + "px";
2858
+ list.appendChild( item );
2767
2859
 
2768
2860
  // Callbacks
2769
2861
  item.addEventListener("click", e => {
2770
- if( handled ) {
2862
+ if( handled )
2863
+ {
2771
2864
  handled = false;
2772
2865
  return;
2773
2866
  }
2774
2867
 
2775
- if( !e.shiftKey ) {
2868
+ if( !e.shiftKey )
2869
+ {
2776
2870
  list.querySelectorAll( "li" ).forEach( e => { e.classList.remove( 'selected' ); } );
2777
2871
  this.selected.length = 0;
2778
2872
  }
@@ -2788,16 +2882,18 @@ class NodeTree {
2788
2882
  }
2789
2883
 
2790
2884
  // Only Show children...
2791
- if( is_parent && node.id.length > 1 /* Strange case... */) {
2885
+ if( isParent && node.id.length > 1 /* Strange case... */) {
2792
2886
  node.closed = false;
2793
- if( that.onevent ) {
2794
- const event = new TreeEvent(TreeEvent.NODE_CARETCHANGED, node, node.closed);
2887
+ if( that.onevent )
2888
+ {
2889
+ const event = new TreeEvent( TreeEvent.NODE_CARETCHANGED, node, node.closed );
2795
2890
  that.onevent( event );
2796
2891
  }
2797
2892
  that.frefresh( node.id );
2798
2893
  }
2799
2894
 
2800
- if( that.onevent ) {
2895
+ if( that.onevent )
2896
+ {
2801
2897
  const event = new TreeEvent(TreeEvent.NODE_SELECTED, e.shiftKey ? this.selected : node );
2802
2898
  event.multiple = e.shiftKey;
2803
2899
  that.onevent( event );
@@ -2820,85 +2916,87 @@ class NodeTree {
2820
2916
  }
2821
2917
  });
2822
2918
 
2823
- item.addEventListener("contextmenu", e => {
2919
+ item.addEventListener( "contextmenu", e => {
2920
+
2824
2921
  e.preventDefault();
2825
- if(that.onevent) {
2826
- const event = new TreeEvent(TreeEvent.NODE_CONTEXTMENU, this.selected.length > 1 ? this.selected : node, e);
2827
- event.multiple = this.selected.length > 1;
2828
2922
 
2829
- LX.addContextMenu( event.multiple ? "Selected Nodes" : event.node.id, event.value, m => {
2830
- event.panel = m;
2831
- });
2923
+ if( that.onevent )
2924
+ {
2925
+ return;
2926
+ }
2832
2927
 
2833
- that.onevent( event );
2928
+ const event = new TreeEvent(TreeEvent.NODE_CONTEXTMENU, this.selected.length > 1 ? this.selected : node, e);
2929
+ event.multiple = this.selected.length > 1;
2930
+
2931
+ LX.addContextMenu( event.multiple ? "Selected Nodes" : event.node.id, event.value, m => {
2932
+ event.panel = m;
2933
+ });
2834
2934
 
2835
- if( ( this.options.addDefault ?? false ) == true )
2935
+ that.onevent( event );
2936
+
2937
+ if( ( this.options.addDefault ?? false ) == true )
2938
+ {
2939
+ if( event.panel.items )
2836
2940
  {
2837
- if( event.panel.items )
2838
- {
2839
- event.panel.add( "" );
2840
- }
2841
-
2842
- event.panel.add( "Select Children", () => {
2843
-
2844
- const selectChildren = ( n ) => {
2845
-
2846
- if( n.closed )
2847
- {
2848
- return;
2849
- }
2850
-
2851
- for( let child of n.children ?? [] )
2852
- {
2853
- if( !child )
2854
- {
2855
- continue;
2856
- }
2857
-
2858
- let nodeItem = this.domEl.querySelector( '#' + child.id );
2859
- nodeItem.classList.add('selected');
2860
- this.selected.push( child );
2861
- selectChildren( child );
2862
- }
2863
- };
2864
-
2865
- // Add childs of the clicked node
2866
- selectChildren( node );
2867
-
2868
- } );
2869
-
2870
- // event.panel.add( "Clone", { callback: () => {
2871
-
2872
- // } } );
2873
-
2874
- event.panel.add( "Delete", { callback: () => {
2875
-
2876
- // It's the root node
2877
- if( !node.parent )
2941
+ event.panel.add( "" );
2942
+ }
2943
+
2944
+ event.panel.add( "Select Children", () => {
2945
+
2946
+ const selectChildren = ( n ) => {
2947
+
2948
+ if( n.closed )
2878
2949
  {
2879
2950
  return;
2880
2951
  }
2881
-
2882
- if( that.onevent ) {
2883
- const event = new TreeEvent( TreeEvent.NODE_DELETED, node, e );
2884
- that.onevent( event );
2952
+
2953
+ for( let child of n.children ?? [] )
2954
+ {
2955
+ if( !child )
2956
+ {
2957
+ continue;
2958
+ }
2959
+
2960
+ let nodeItem = this.domEl.querySelector( '#' + child.id );
2961
+ nodeItem.classList.add('selected');
2962
+ this.selected.push( child );
2963
+ selectChildren( child );
2885
2964
  }
2886
-
2887
- // Delete nodes now
2888
- let childs = node.parent.children;
2889
- const index = childs.indexOf( node );
2890
- childs.splice( index, 1 );
2891
-
2892
- this.refresh();
2893
- } } );
2894
- }
2965
+ };
2966
+
2967
+ // Add childs of the clicked node
2968
+ selectChildren( node );
2969
+ } );
2970
+
2971
+ event.panel.add( "Delete", { callback: () => {
2972
+
2973
+ // It's the root node
2974
+ if( !node.parent )
2975
+ {
2976
+ return;
2977
+ }
2978
+
2979
+ if( that.onevent ) {
2980
+ const event = new TreeEvent( TreeEvent.NODE_DELETED, node, e );
2981
+ that.onevent( event );
2982
+ }
2983
+
2984
+ // Delete nodes now
2985
+ let childs = node.parent.children;
2986
+ const index = childs.indexOf( node );
2987
+ childs.splice( index, 1 );
2988
+
2989
+ this.refresh();
2990
+ } } );
2895
2991
  }
2896
2992
  });
2897
2993
 
2898
2994
  item.addEventListener("keydown", e => {
2899
2995
 
2900
2996
  if( node.rename )
2997
+ {
2901
2998
  return;
2999
+ }
2902
3000
 
2903
3001
  e.preventDefault();
2904
3002
 
@@ -2927,7 +3025,10 @@ class NodeTree {
2927
3025
  var selected = this.selected.length > 1 ? ( e.key == "ArrowUp" ? this.selected.shift() : this.selected.pop() ) : this.selected[ 0 ];
2928
3026
  var el = this.domEl.querySelector( "#" + LX.getSupportedDOMName( selected.id ) );
2929
3027
  var sibling = e.key == "ArrowUp" ? el.previousSibling : el.nextSibling;
2930
- if( sibling ) sibling.click();
3028
+ if( sibling )
3029
+ {
3030
+ sibling.click();
3031
+ }
2931
3032
  }
2932
3033
  });
2933
3034
 
@@ -3033,7 +3134,7 @@ class NodeTree {
3033
3134
  let handled = false;
3034
3135
 
3035
3136
  // Show/hide children
3036
- if(is_parent) {
3137
+ if(isParent) {
3037
3138
  item.querySelector('a.hierarchy').addEventListener("click", function(e) {
3038
3139
 
3039
3140
  handled = true;
@@ -3171,19 +3272,25 @@ class Panel {
3171
3272
  getValue( name ) {
3172
3273
 
3173
3274
  let widget = this.widgets[ name ];
3174
- if(!widget)
3175
- throw("No widget called " + name);
3275
+
3276
+ if( !widget )
3277
+ {
3278
+ throw( "No widget called " + name );
3279
+ }
3176
3280
 
3177
3281
  return widget.value();
3178
3282
  }
3179
3283
 
3180
- setValue( name, value ) {
3284
+ setValue( name, value, skipCallback ) {
3181
3285
 
3182
3286
  let widget = this.widgets[ name ];
3183
- if(!widget)
3184
- throw("No widget called " + name);
3185
3287
 
3186
- return widget.set(value);
3288
+ if( !widget )
3289
+ {
3290
+ throw( "No widget called " + name );
3291
+ }
3292
+
3293
+ return widget.set( value, skipCallback );
3187
3294
  }
3188
3295
 
3189
3296
  /**
@@ -3363,8 +3470,8 @@ class Panel {
3363
3470
  }
3364
3471
 
3365
3472
  static _dispatch_event( element, type, data, bubbles, cancelable ) {
3366
- let event = new CustomEvent(type, { 'detail': data, 'bubbles': bubbles, 'cancelable': cancelable });
3367
- element.dispatchEvent(event);
3473
+ let event = new CustomEvent( type, { 'detail': data, 'bubbles': bubbles, 'cancelable': cancelable } );
3474
+ element.dispatchEvent( event );
3368
3475
  }
3369
3476
 
3370
3477
  static _add_reset_property( container, callback ) {
@@ -3372,8 +3479,8 @@ class Panel {
3372
3479
  domEl.style.display = "none";
3373
3480
  domEl.style.marginRight = "6px";
3374
3481
  domEl.className = "lexicon fa fa-rotate-left";
3375
- domEl.addEventListener("click", callback);
3376
- container.appendChild(domEl);
3482
+ domEl.addEventListener( "click", callback );
3483
+ container.appendChild( domEl );
3377
3484
  return domEl;
3378
3485
  }
3379
3486
 
@@ -3383,39 +3490,45 @@ class Panel {
3383
3490
 
3384
3491
  create_widget( name, type, options = {} ) {
3385
3492
 
3386
- let widget = new Widget(name, type, options);
3493
+ let widget = new Widget( name, type, options );
3387
3494
 
3388
- let element = document.createElement('div');
3495
+ let element = document.createElement( 'div' );
3389
3496
  element.className = "lexwidget";
3390
- if(options.id)
3391
- element.id = options.id;
3392
- if(options.className)
3497
+ element.id = options.id ?? "";
3498
+ element.title = options.title ?? "";
3499
+
3500
+ if( options.className )
3501
+ {
3393
3502
  element.className += " " + options.className;
3394
- if(options.title)
3395
- element.title = options.title;
3503
+ }
3396
3504
 
3397
3505
  if( type != Widget.TITLE )
3398
3506
  {
3399
3507
  element.style.width = "calc(100% - " + (this.current_branch || type == Widget.FILE ? 10 : 20) + "px)";
3400
- if( options.width ) {
3508
+
3509
+ if( options.width )
3510
+ {
3401
3511
  element.style.width = element.style.minWidth = options.width;
3402
3512
  }
3403
- if( options.maxWidth ) {
3513
+ if( options.maxWidth )
3514
+ {
3404
3515
  element.style.maxWidth = options.maxWidth;
3405
3516
  }
3406
- if( options.minWidth ) {
3517
+ if( options.minWidth )
3518
+ {
3407
3519
  element.style.minWidth = options.minWidth;
3408
3520
  }
3409
- if( options.height ) {
3521
+ if( options.height )
3522
+ {
3410
3523
  element.style.height = element.style.minHeight = options.height;
3411
3524
  }
3412
3525
  }
3413
3526
 
3414
- if(name != undefined) {
3415
-
3416
- if(!(options.no_name ?? false) )
3527
+ if( name != undefined )
3528
+ {
3529
+ if( !(options.no_name ?? false) )
3417
3530
  {
3418
- let domName = document.createElement('div');
3531
+ let domName = document.createElement( 'div' );
3419
3532
  domName.className = "lexwidgetname";
3420
3533
  if( options.justifyName )
3421
3534
  {
@@ -3428,22 +3541,27 @@ class Panel {
3428
3541
  element.domName = domName;
3429
3542
 
3430
3543
  // Copy-paste info
3431
- domName.addEventListener('contextmenu', function(e) {
3544
+ domName.addEventListener('contextmenu', function( e ) {
3432
3545
  e.preventDefault();
3433
- widget.oncontextmenu(e);
3546
+ widget.oncontextmenu( e );
3434
3547
  });
3435
3548
  }
3436
3549
 
3437
3550
  this.widgets[ name ] = widget;
3438
3551
  }
3439
3552
 
3440
- if(options.signal)
3553
+ if( options.signal )
3441
3554
  {
3442
- if(!name) {
3443
- if(!this.signals)
3555
+ if( !name )
3556
+ {
3557
+ if( !this.signals )
3558
+ {
3444
3559
  this.signals = [];
3445
- this.signals.push({[options.signal]: widget})
3560
+ }
3561
+
3562
+ this.signals.push( { [ options.signal ]: widget } )
3446
3563
  }
3564
+
3447
3565
  LX.addSignal( options.signal, widget );
3448
3566
  }
3449
3567
 
@@ -5103,6 +5221,8 @@ class Panel {
5103
5221
  * min, max: Min and Max values for the input
5104
5222
  * skipSlider: If there are min and max values, skip the slider
5105
5223
  * units: Unit as string added to the end of the value
5224
+ * onPress: Callback function on mouse down
5225
+ * onRelease: Callback function on mouse up
5106
5226
  */
5107
5227
 
5108
5228
  addNumber( name, value, callback, options = {} ) {
@@ -5112,6 +5232,7 @@ class Panel {
5112
5232
  widget.onGetValue = () => {
5113
5233
  return +vecinput.value;
5114
5234
  };
5235
+
5115
5236
  widget.onSetValue = ( newValue, skipCallback ) => {
5116
5237
  vecinput.value = round( newValue, options.precision );
5117
5238
  Panel._dispatch_event( vecinput, "change", skipCallback );
@@ -5154,16 +5275,6 @@ class Panel {
5154
5275
  vecinput.value = vecinput.iValue = value;
5155
5276
  box.appendChild( vecinput );
5156
5277
 
5157
- let measureRealWidth = function( value, paddingPlusMargin = 8 ) {
5158
- var i = document.createElement( "span" );
5159
- i.className = "lexinputmeasure";
5160
- i.innerHTML = value;
5161
- document.body.appendChild( i );
5162
- var rect = i.getBoundingClientRect();
5163
- LX.UTILS.deleteElement( i );
5164
- return rect.width + paddingPlusMargin;
5165
- }
5166
-
5167
5278
  if( options.units )
5168
5279
  {
5169
5280
  let unitSpan = document.createElement( 'span' );
@@ -5183,21 +5294,47 @@ class Panel {
5183
5294
  vecinput.disabled = true;
5184
5295
  }
5185
5296
 
5186
- // add slider below
5187
- if( !options.skipSlider && options.min !== undefined && options.max !== undefined ) {
5297
+ // Add slider below
5298
+ if( !options.skipSlider && options.min !== undefined && options.max !== undefined )
5299
+ {
5188
5300
  let slider = document.createElement( 'input' );
5189
5301
  slider.className = "lexinputslider";
5190
- slider.step = options.step ?? 1;
5191
5302
  slider.min = options.min;
5192
5303
  slider.max = options.max;
5304
+ slider.step = options.step ?? 1;
5193
5305
  slider.type = "range";
5194
5306
  slider.value = value;
5307
+
5195
5308
  slider.addEventListener( "input", function( e ) {
5196
5309
  let new_value = +this.valueAsNumber;
5197
5310
  vecinput.value = round( new_value, options.precision );
5198
5311
  Panel._dispatch_event( vecinput, "change" );
5199
5312
  }, false );
5313
+
5314
+ slider.addEventListener( "mousedown", function( e ) {
5315
+ if( options.onPress )
5316
+ {
5317
+ options.onPress.bind( slider )( e, slider );
5318
+ }
5319
+ }, false );
5320
+
5321
+ slider.addEventListener( "mouseup", function( e ) {
5322
+ if( options.onRelease )
5323
+ {
5324
+ options.onRelease.bind( slider )( e, slider );
5325
+ }
5326
+ }, false );
5327
+
5200
5328
  box.appendChild( slider );
5329
+
5330
+ // Method to change min, max, step parameters
5331
+ widget.setLimits = ( newMin, newMax, newStep ) => {
5332
+ vecinput.min = slider.min = newMin ?? vecinput.min;
5333
+ vecinput.max = slider.max = newMax ?? vecinput.max;
5334
+ vecinput.step = newStep ?? vecinput.step;
5335
+ slider.step = newStep ?? slider.step;
5336
+ Panel._dispatch_event( vecinput, "change", true );
5337
+ };
5201
5338
  }
5202
5339
 
5203
5340
  // Add wheel input
@@ -5205,7 +5342,9 @@ class Panel {
5205
5342
  vecinput.addEventListener( "wheel", function( e ) {
5206
5343
  e.preventDefault();
5207
5344
  if( this !== document.activeElement )
5345
+ {
5208
5346
  return;
5347
+ }
5209
5348
  let mult = options.step ?? 1;
5210
5349
  if( e.shiftKey ) mult *= 10;
5211
5350
  else if( e.altKey ) mult *= 0.1;
@@ -5217,7 +5356,9 @@ class Panel {
5217
5356
  vecinput.addEventListener( "change", e => {
5218
5357
 
5219
5358
  if( isNaN( e.target.valueAsNumber ) )
5359
+ {
5220
5360
  return;
5361
+ }
5221
5362
 
5222
5363
  const skipCallback = e.detail;
5223
5364
 
@@ -5253,27 +5394,39 @@ class Panel {
5253
5394
 
5254
5395
  var that = this;
5255
5396
  var lastY = 0;
5256
- function inner_mousedown(e) {
5257
- if(document.activeElement == vecinput) return;
5397
+
5398
+ function inner_mousedown( e )
5399
+ {
5400
+ if( document.activeElement == vecinput )
5401
+ {
5402
+ return;
5403
+ }
5404
+
5258
5405
  var doc = that.root.ownerDocument;
5259
- doc.addEventListener("mousemove",inner_mousemove);
5260
- doc.addEventListener("mouseup",inner_mouseup);
5406
+ doc.addEventListener( 'mousemove', inner_mousemove );
5407
+ doc.addEventListener( 'mouseup', inner_mouseup );
5261
5408
  lastY = e.pageY;
5262
- document.body.classList.add('nocursor');
5263
- document.body.classList.add('noevents');
5264
- dragIcon.classList.remove('hidden');
5409
+ document.body.classList.add( 'nocursor' );
5410
+ document.body.classList.add( 'noevents' );
5411
+ dragIcon.classList.remove( 'hidden' );
5265
5412
  e.stopImmediatePropagation();
5266
5413
  e.stopPropagation();
5414
+
5415
+ if( options.onPress )
5416
+ {
5417
+ options.onPress.bind( vecinput )( e, vecinput );
5418
+ }
5267
5419
  }
5268
5420
 
5269
- function inner_mousemove(e) {
5270
- if (lastY != e.pageY) {
5421
+ function inner_mousemove( e )
5422
+ {
5423
+ if ( lastY != e.pageY ) {
5271
5424
  let dt = lastY - e.pageY;
5272
5425
  let mult = options.step ?? 1;
5273
- if(e.shiftKey) mult *= 10;
5274
- else if(e.altKey) mult *= 0.1;
5275
- let new_value = (+vecinput.valueAsNumber + mult * dt);
5276
- vecinput.value = (+new_value).toFixed( 4 ).replace(/([0-9]+(\.[0-9]+[1-9])?)(\.?0+$)/,'$1');
5426
+ if( e.shiftKey ) mult *= 10;
5427
+ else if( e.altKey ) mult *= 0.1;
5428
+ let new_value = ( +vecinput.valueAsNumber + mult * dt );
5429
+ vecinput.value = ( +new_value ).toFixed( 4 ).replace( /([0-9]+(\.[0-9]+[1-9])?)(\.?0+$)/, '$1' );
5277
5430
  Panel._dispatch_event( vecinput, "change" );
5278
5431
  }
5279
5432
 
@@ -5282,20 +5435,27 @@ class Panel {
5282
5435
  e.preventDefault();
5283
5436
  }
5284
5437
 
5285
- function inner_mouseup(e) {
5438
+ function inner_mouseup( e )
5439
+ {
5286
5440
  var doc = that.root.ownerDocument;
5287
- doc.removeEventListener("mousemove",inner_mousemove);
5288
- doc.removeEventListener("mouseup",inner_mouseup);
5289
- document.body.classList.remove('nocursor');
5290
- document.body.classList.remove('noevents');
5291
- dragIcon.classList.add('hidden');
5441
+ doc.removeEventListener( 'mousemove', inner_mousemove );
5442
+ doc.removeEventListener( 'mouseup', inner_mouseup );
5443
+ document.body.classList.remove( 'nocursor' );
5444
+ document.body.classList.remove( 'noevents' );
5445
+ dragIcon.classList.add( 'hidden' );
5446
+
5447
+ if( options.onRelease )
5448
+ {
5449
+ options.onRelease.bind( vecinput )( e, vecinput );
5450
+ }
5292
5451
  }
5293
5452
 
5294
- container.appendChild(box);
5295
- element.appendChild(container);
5453
+ container.appendChild( box );
5454
+ element.appendChild( container );
5296
5455
 
5297
5456
  // Remove branch padding and margins
5298
- if(!widget.name) {
5457
+ if( !widget.name )
5458
+ {
5299
5459
  element.className += " noname";
5300
5460
  container.style.width = "100%";
5301
5461
  }
@@ -5303,14 +5463,15 @@ class Panel {
5303
5463
  return widget;
5304
5464
  }
5305
5465
 
5306
- static VECTOR_COMPONENTS = {0: 'x', 1: 'y', 2: 'z', 3: 'w'};
5466
+ static VECTOR_COMPONENTS = { 0: 'x', 1: 'y', 2: 'z', 3: 'w' };
5307
5467
 
5308
5468
  _add_vector( num_components, name, value, callback, options = {} ) {
5309
5469
 
5310
5470
  num_components = clamp( num_components, 2, 4 );
5311
5471
  value = value ?? new Array( num_components ).fill( 0 );
5312
5472
 
5313
- if( !name ) {
5473
+ if( !name )
5474
+ {
5314
5475
  throw( "Set Widget Name!" );
5315
5476
  }
5316
5477
 
@@ -5320,9 +5481,12 @@ class Panel {
5320
5481
  let inputs = element.querySelectorAll( "input" );
5321
5482
  let value = [];
5322
5483
  for( var v of inputs )
5484
+ {
5323
5485
  value.push( +v.value );
5486
+ }
5324
5487
  return value;
5325
5488
  };
5489
+
5326
5490
  widget.onSetValue = ( newValue, skipCallback ) => {
5327
5491
  const inputs = element.querySelectorAll( ".vecinput" );
5328
5492
  if( inputs.length == newValue.length )
@@ -5331,7 +5495,7 @@ class Panel {
5331
5495
  return;
5332
5496
  }
5333
5497
 
5334
- for( var i = 0; i < inputs.length; ++i ) {
5498
+ for( let i = 0; i < inputs.length; ++i ) {
5335
5499
  let value = newValue[ i ];
5336
5500
  inputs[ i ].value = round( value, options.precision ) ?? 0;
5337
5501
  Panel._dispatch_event( inputs[ i ], "change", skipCallback );
@@ -5351,7 +5515,7 @@ class Panel {
5351
5515
 
5352
5516
  // Add widget value
5353
5517
 
5354
- var container = document.createElement('div');
5518
+ var container = document.createElement( 'div' );
5355
5519
  container.className = "lexvector";
5356
5520
  container.style.width = "calc( 100% - " + LX.DEFAULT_NAME_WIDTH + ")";
5357
5521
 
@@ -5382,12 +5546,12 @@ class Panel {
5382
5546
  dragIcon.className = "fa-solid fa-arrows-up-down drag-icon hidden";
5383
5547
  box.appendChild( dragIcon );
5384
5548
 
5385
- if( options.disabled ) {
5549
+ if( options.disabled )
5550
+ {
5386
5551
  vecinput.disabled = true;
5387
5552
  }
5388
5553
 
5389
5554
  // Add wheel input
5390
-
5391
5555
  vecinput.addEventListener( "wheel", function( e ) {
5392
5556
  e.preventDefault();
5393
5557
  if( this !== document.activeElement )
@@ -5401,7 +5565,7 @@ class Panel {
5401
5565
  for( let v of element.querySelectorAll(".vecinput") )
5402
5566
  {
5403
5567
  v.value = round( +v.valueAsNumber - mult * ( e.deltaY > 0 ? 1 : -1 ), options.precision );
5404
- Panel._dispatch_event(v, "change");
5568
+ Panel._dispatch_event( v, "change" );
5405
5569
  }
5406
5570
  }
5407
5571
  else
@@ -5434,7 +5598,8 @@ class Panel {
5434
5598
  v.value = val;
5435
5599
  value[ v.idx ] = val;
5436
5600
  }
5437
- } else {
5601
+ } else
5602
+ {
5438
5603
  vecinput.value = val;
5439
5604
  value[ e.target.idx ] = val;
5440
5605
  }
@@ -5448,35 +5613,48 @@ class Panel {
5448
5613
 
5449
5614
  var that = this;
5450
5615
  var lastY = 0;
5451
- function inner_mousedown(e) {
5452
- if(document.activeElement == vecinput) return;
5616
+ function inner_mousedown( e )
5617
+ {
5618
+ if( document.activeElement == vecinput )
5619
+ {
5620
+ return;
5621
+ }
5622
+
5453
5623
  var doc = that.root.ownerDocument;
5454
- doc.addEventListener("mousemove",inner_mousemove);
5455
- doc.addEventListener("mouseup",inner_mouseup);
5624
+ doc.addEventListener( 'mousemove', inner_mousemove );
5625
+ doc.addEventListener( 'mouseup', inner_mouseup );
5456
5626
  lastY = e.pageY;
5457
- document.body.classList.add('nocursor');
5458
- document.body.classList.add('noevents');
5459
- dragIcon.classList.remove('hidden');
5627
+ document.body.classList.add( 'nocursor' );
5628
+ document.body.classList.add( 'noevents' );
5629
+ dragIcon.classList.remove( 'hidden' );
5460
5630
  e.stopImmediatePropagation();
5461
5631
  e.stopPropagation();
5632
+
5633
+ if( options.onPress )
5634
+ {
5635
+ options.onPress.bind( vecinput )( e, vecinput );
5636
+ }
5462
5637
  }
5463
5638
 
5464
- function inner_mousemove(e) {
5465
- if (lastY != e.pageY) {
5639
+ function inner_mousemove( e )
5640
+ {
5641
+ if ( lastY != e.pageY ) {
5466
5642
  let dt = lastY - e.pageY;
5467
5643
  let mult = options.step ?? 1;
5468
- if(e.shiftKey) mult = 10;
5469
- else if(e.altKey) mult = 0.1;
5644
+ if( e.shiftKey ) mult = 10;
5645
+ else if( e.altKey ) mult = 0.1;
5470
5646
 
5471
5647
  if( locker.locked )
5472
5648
  {
5473
- for( let v of element.querySelectorAll(".vecinput") ) {
5649
+ for( let v of element.querySelectorAll( ".vecinput" ) ) {
5474
5650
  v.value = round( +v.valueAsNumber + mult * dt, options.precision );
5475
- Panel._dispatch_event(v, "change");
5651
+ Panel._dispatch_event( v, "change" );
5476
5652
  }
5477
- } else {
5653
+ }
5654
+ else
5655
+ {
5478
5656
  vecinput.value = round( +vecinput.valueAsNumber + mult * dt, options.precision );
5479
- Panel._dispatch_event(vecinput, "change");
5657
+ Panel._dispatch_event( vecinput, "change" );
5480
5658
  }
5481
5659
  }
5482
5660
 
@@ -5485,32 +5663,57 @@ class Panel {
5485
5663
  e.preventDefault();
5486
5664
  }
5487
5665
 
5488
- function inner_mouseup( e ) {
5666
+ function inner_mouseup( e )
5667
+ {
5489
5668
  var doc = that.root.ownerDocument;
5490
- doc.removeEventListener("mousemove",inner_mousemove);
5491
- doc.removeEventListener("mouseup",inner_mouseup);
5492
- document.body.classList.remove('nocursor');
5493
- document.body.classList.remove('noevents');
5669
+ doc.removeEventListener( 'mousemove', inner_mousemove );
5670
+ doc.removeEventListener( 'mouseup', inner_mouseup );
5671
+ document.body.classList.remove( 'nocursor' );
5672
+ document.body.classList.remove( 'noevents' );
5494
5673
  dragIcon.classList.add('hidden');
5674
+
5675
+ if( options.onRelease )
5676
+ {
5677
+ options.onRelease.bind( vecinput )( e, vecinput );
5678
+ }
5495
5679
  }
5496
5680
 
5497
5681
  box.appendChild( vecinput );
5498
5682
  container.appendChild( box );
5499
5683
  }
5500
5684
 
5501
- let locker = document.createElement('a');
5685
+ // Method to change min, max, step parameters
5686
+ if( options.min !== undefined || options.max !== undefined )
5687
+ {
5688
+ widget.setLimits = ( newMin, newMax, newStep ) => {
5689
+ const inputs = element.querySelectorAll(".vecinput");
5690
+ for( let v of inputs )
5691
+ {
5692
+ v.min = newMin ?? v.min;
5693
+ v.max = newMax ?? v.max;
5694
+ v.step = newStep ?? v.step;
5695
+ Panel._dispatch_event( v, "change", true );
5696
+ }
5697
+
5698
+ // To call onChange callback
5699
+ this._trigger( new IEvent( name, value ), callback );
5700
+ };
5701
+ }
5702
+
5703
+ let locker = document.createElement( 'a' );
5502
5704
  locker.className = "fa-solid fa-lock-open lexicon";
5503
- container.appendChild(locker);
5504
- locker.addEventListener("click", function(e) {
5705
+ container.appendChild( locker );
5706
+ locker.addEventListener( "click", function( e ) {
5505
5707
  this.locked = !this.locked;
5506
- if(this.locked){
5507
- this.classList.add("fa-lock");
5508
- this.classList.remove("fa-lock-open");
5708
+ if( this.locked )
5709
+ {
5710
+ this.classList.add( "fa-lock" );
5711
+ this.classList.remove( "fa-lock-open" );
5509
5712
  } else {
5510
- this.classList.add("fa-lock-open");
5511
- this.classList.remove("fa-lock");
5713
+ this.classList.add( "fa-lock-open" );
5714
+ this.classList.remove( "fa-lock" );
5512
5715
  }
5513
- }, false);
5716
+ }, false );
5514
5717
 
5515
5718
  element.appendChild( container );
5516
5719
 
@@ -5526,21 +5729,231 @@ class Panel {
5526
5729
  * disabled: Make the widget disabled [false]
5527
5730
  * step: Step of the inputs
5528
5731
  * min, max: Min and Max values for the inputs
5732
+ * onPress: Callback function on mouse down
5733
+ * onRelease: Callback function on mouse is released
5529
5734
  */
5530
5735
 
5531
5736
  addVector2( name, value, callback, options ) {
5532
5737
 
5533
- return this._add_vector(2, name, value, callback, options);
5738
+ return this._add_vector( 2, name, value, callback, options );
5534
5739
  }
5535
5740
 
5536
5741
  addVector3( name, value, callback, options ) {
5537
5742
 
5538
- return this._add_vector(3, name, value, callback, options);
5743
+ return this._add_vector( 3, name, value, callback, options );
5539
5744
  }
5540
5745
 
5541
5746
  addVector4( name, value, callback, options ) {
5542
5747
 
5543
- return this._add_vector(4, name, value, callback, options);
5748
+ return this._add_vector( 4, name, value, callback, options );
5749
+ }
5750
+
5751
+ /**
5752
+ * @method addSize
5753
+ * @param {String} name Widget name
5754
+ * @param {Number} value Default number value
5755
+ * @param {Function} callback Callback function on change
5756
+ * @param {*} options:
5757
+ * disabled: Make the widget disabled [false]
5758
+ * units: Unit as string added to the end of the value
5759
+ */
5760
+
5761
+ addSize( name, value, callback, options = {} ) {
5762
+
5763
+ let widget = this.create_widget( name, Widget.SIZE, options );
5764
+
5765
+ widget.onGetValue = () => {
5766
+ const value = [];
5767
+ for( let i = 0; i < element.dimensions.length; ++i )
5768
+ {
5769
+ value.push( element.dimensions[ i ].onGetValue() );
5770
+ }
5771
+ return value;
5772
+ };
5773
+
5774
+ widget.onSetValue = ( newValue, skipCallback ) => {
5775
+ for( let i = 0; i < element.dimensions.length; ++i )
5776
+ {
5777
+ element.dimensions[ i ].onSetValue( newValue[ i ], skipCallback );
5778
+ }
5779
+ };
5780
+
5781
+ let element = widget.domEl;
5782
+
5783
+ this.queue( element );
5784
+
5785
+ element.dimensions = [];
5786
+
5787
+ for( let i = 0; i < value.length; ++i )
5788
+ {
5789
+ const size = measureRealWidth( JSON.stringify( value[ i ] ), 24 ) + 'px';
5790
+ element.dimensions[ i ] = this.addNumber( null, value[ i ], ( v ) => {
5791
+
5792
+ const value = [];
5793
+
5794
+ for( let i = 0; i < element.dimensions.length; ++i )
5795
+ {
5796
+ value.push( element.dimensions[ i ].onGetValue() );
5797
+ }
5798
+
5799
+ if( callback )
5800
+ {
5801
+ callback( value );
5802
+ }
5803
+
5804
+ }, { width: size, min: 0, disabled: options.disabled } );
5805
+
5806
+ if( ( i + 1 ) != value.length )
5807
+ {
5808
+ let cross = document.createElement( 'a' );
5809
+ cross.className = "lexsizecross fa-solid fa-xmark";
5810
+ element.appendChild( cross );
5811
+ }
5812
+ }
5813
+
5814
+ this.clearQueue();
5815
+
5816
+ if( options.units )
5817
+ {
5818
+ let unitSpan = document.createElement( 'span' );
5819
+ unitSpan.className = "lexunit";
5820
+ unitSpan.innerText = options.units;
5821
+ element.appendChild( unitSpan );
5822
+ }
5823
+
5824
+ // Remove branch padding and margins
5825
+ if( !widget.name )
5826
+ {
5827
+ element.className += " noname";
5828
+ container.style.width = "100%";
5829
+ }
5830
+
5831
+ return widget;
5832
+ }
5833
+
5834
+ /**
5835
+ * @method addPad
5836
+ * @param {String} name Widget name
5837
+ * @param {Number} value Pad value
5838
+ * @param {Function} callback Callback function on change
5839
+ * @param {*} options:
5840
+ * disabled: Make the widget disabled [false]
5841
+ * min, max: Min and Max values
5842
+ * onPress: Callback function on mouse down
5843
+ * onRelease: Callback function on mouse up
5844
+ */
5845
+
5846
+ addPad( name, value, callback, options = {} ) {
5847
+
5848
+ if( !name )
5849
+ {
5850
+ throw( "Set Widget Name!" );
5851
+ }
5852
+
5853
+ let widget = this.create_widget( name, Widget.PAD, options );
5854
+
5855
+ widget.onGetValue = () => {
5856
+ return thumb.value.xy;
5857
+ };
5858
+
5859
+ widget.onSetValue = ( newValue, skipCallback ) => {
5860
+ thumb.value.set( newValue[ 0 ], newValue[ 1 ] );
5861
+ _updateValue( thumb.value );
5862
+ if( !skipCallback )
5863
+ {
5864
+ this._trigger( new IEvent( name, thumb.value.xy ), callback );
5865
+ }
5866
+ };
5867
+
5868
+ let element = widget.domEl;
5869
+
5870
+ var container = document.createElement( 'div' );
5871
+ container.className = "lexpad";
5872
+ container.style.width = "calc( 100% - " + LX.DEFAULT_NAME_WIDTH + ")";
5873
+
5874
+ let pad = document.createElement('div');
5875
+ pad.id = "lexpad-" + name;
5876
+ pad.className = "lexinnerpad";
5877
+ pad.style.width = options.padSize ?? '96px';
5878
+ pad.style.height = options.padSize ?? '96px';
5879
+
5880
+ let thumb = document.createElement('div');
5881
+ thumb.className = "lexpadthumb";
5882
+ thumb.value = new LX.vec2( value[ 0 ], value[ 1 ] );
5883
+ thumb.min = options.min ?? 0;
5884
+ thumb.max = options.max ?? 1;
5885
+
5886
+ let _updateValue = v => {
5887
+ const [ w, h ] = [ pad.offsetWidth, pad.offsetHeight ];
5888
+ 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 ) );
5889
+ thumb.style.transform = `translate(calc( ${ w * value0to1.x }px - 50% ), calc( ${ h * value0to1.y }px - 50%)`;
5890
+ }
5891
+
5892
+ doAsync( () => {
5893
+ _updateValue( thumb.value )
5894
+ } );
5895
+
5896
+ pad.appendChild( thumb );
5897
+ container.appendChild( pad );
5898
+ element.appendChild( container );
5899
+
5900
+ pad.addEventListener( "mousedown", innerMouseDown );
5901
+
5902
+ let that = this;
5903
+
5904
+ function innerMouseDown( e )
5905
+ {
5906
+ if( document.activeElement == thumb )
5907
+ {
5908
+ return;
5909
+ }
5910
+
5911
+ var doc = that.root.ownerDocument;
5912
+ doc.addEventListener( 'mousemove', innerMouseMove );
5913
+ doc.addEventListener( 'mouseup', innerMouseUp );
5914
+ document.body.classList.add( 'nocursor' );
5915
+ document.body.classList.add( 'noevents' );
5916
+ e.stopImmediatePropagation();
5917
+ e.stopPropagation();
5918
+
5919
+ if( options.onPress )
5920
+ {
5921
+ options.onPress.bind( thumb )( e, thumb );
5922
+ }
5923
+ }
5924
+
5925
+ function innerMouseMove( e )
5926
+ {
5927
+ const rect = pad.getBoundingClientRect();
5928
+ const relativePosition = new LX.vec2( e.x - rect.x, e.y - rect.y );
5929
+ relativePosition.clp( 0.0, pad.offsetWidth, relativePosition);
5930
+ const [ w, h ] = [ pad.offsetWidth, pad.offsetHeight ];
5931
+ const value0to1 = relativePosition.div( new LX.vec2( pad.offsetWidth, pad.offsetHeight ) );
5932
+
5933
+ thumb.style.transform = `translate(calc( ${ w * value0to1.x }px - 50% ), calc( ${ h * value0to1.y }px - 50%)`;
5934
+ 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 ) );
5935
+
5936
+ that._trigger( new IEvent( name, thumb.value.xy, e ), callback );
5937
+
5938
+ e.stopPropagation();
5939
+ e.preventDefault();
5940
+ }
5941
+
5942
+ function innerMouseUp( e )
5943
+ {
5944
+ var doc = that.root.ownerDocument;
5945
+ doc.removeEventListener( 'mousemove', innerMouseMove );
5946
+ doc.removeEventListener( 'mouseup', innerMouseUp );
5947
+ document.body.classList.remove( 'nocursor' );
5948
+ document.body.classList.remove( 'noevents' );
5949
+
5950
+ if( options.onRelease )
5951
+ {
5952
+ options.onRelease.bind( thumb )( e, thumb );
5953
+ }
5954
+ }
5955
+
5956
+ return widget;
5544
5957
  }
5545
5958
 
5546
5959
  /**
@@ -6046,8 +6459,7 @@ class Branch {
6046
6459
 
6047
6460
  this.grabber = grabber;
6048
6461
 
6049
- function getBranchHeight(){
6050
-
6462
+ function getBranchHeight() {
6051
6463
  return that.root.offsetHeight - that.root.children[0].offsetHeight;
6052
6464
  }
6053
6465
 
@@ -6101,20 +6513,23 @@ class Branch {
6101
6513
  var size = this.grabber.style.marginLeft;
6102
6514
 
6103
6515
  // Update sizes of widgets inside
6104
- for(var i = 0; i < this.widgets.length;i++) {
6516
+ for(var i = 0; i < this.widgets.length; i++) {
6105
6517
 
6106
- let widget = this.widgets[i];
6518
+ let widget = this.widgets[ i ];
6107
6519
  let element = widget.domEl;
6108
6520
 
6109
- if(element.children.length < 2)
6521
+ if( element.children.length < 2 )
6522
+ {
6110
6523
  continue;
6524
+ }
6111
6525
 
6112
- var name = element.children[0];
6113
- var value = element.children[1];
6526
+ var name = element.children[ 0 ];
6527
+ var value = element.children[ 1 ];
6114
6528
 
6115
6529
  name.style.width = size;
6116
6530
  let padding = "0px";
6117
- switch(widget.type) {
6531
+ switch( widget.type )
6532
+ {
6118
6533
  case Widget.FILE:
6119
6534
  padding = "10%";
6120
6535
  break;
@@ -6127,7 +6542,10 @@ class Branch {
6127
6542
  value.style.width = "-webkit-calc( 100% - " + size + " - " + padding + " )";
6128
6543
  value.style.width = "calc( 100% - " + size + " - " + padding + " )";
6129
6544
 
6130
- if(widget.onresize) widget.onresize();
6545
+ if( widget.onresize )
6546
+ {
6547
+ widget.onresize();
6548
+ }
6131
6549
  }
6132
6550
  }
6133
6551
  };
@@ -6144,8 +6562,10 @@ class Dialog {
6144
6562
 
6145
6563
  constructor( title, callback, options = {} ) {
6146
6564
 
6147
- if(!callback)
6148
- console.warn("Content is empty, add some widgets using 'callback' parameter!");
6565
+ if( !callback )
6566
+ {
6567
+ console.warn("Content is empty, add some widgets using 'callback' parameter!");
6568
+ }
6149
6569
 
6150
6570
  this._oncreate = callback;
6151
6571
  this.id = simple_guidGenerator();
@@ -6155,8 +6575,10 @@ class Dialog {
6155
6575
  draggable = options.draggable ?? true,
6156
6576
  modal = options.modal ?? false;
6157
6577
 
6158
- if(modal)
6159
- LX.modal.toggle(false);
6578
+ if( modal )
6579
+ {
6580
+ LX.modal.toggle( false );
6581
+ }
6160
6582
 
6161
6583
  var root = document.createElement('div');
6162
6584
  root.className = "lexdialog " + (options.class ?? "");
@@ -6167,8 +6589,8 @@ class Dialog {
6167
6589
 
6168
6590
  var titleDiv = document.createElement('div');
6169
6591
 
6170
- if(title) {
6171
-
6592
+ if( title )
6593
+ {
6172
6594
  titleDiv.className = "lexdialogtitle";
6173
6595
  titleDiv.innerHTML = title;
6174
6596
  titleDiv.setAttribute('draggable', false);
@@ -6272,7 +6694,9 @@ class Dialog {
6272
6694
  this.title = titleDiv;
6273
6695
 
6274
6696
  if( draggable )
6275
- makeDraggable( root, { targetClass: 'lexdialogtitle' } );
6697
+ {
6698
+ makeDraggable( root, Object.assign( { targetClass: 'lexdialogtitle' }, options ) );
6699
+ }
6276
6700
 
6277
6701
  // Process position and size
6278
6702
  if(size.length && typeof(size[0]) != "string")
@@ -6447,28 +6871,42 @@ class ContextMenu {
6447
6871
  }
6448
6872
  }
6449
6873
 
6450
- _adjust_position(div, margin, useAbsolute = false) {
6874
+ _adjust_position( div, margin, useAbsolute = false ) {
6451
6875
 
6452
6876
  let rect = div.getBoundingClientRect();
6453
6877
 
6454
- if(!useAbsolute)
6878
+ if( !useAbsolute )
6455
6879
  {
6456
6880
  let width = rect.width;
6457
- if(window.innerWidth - rect.right < 0)
6881
+ if( rect.left < 0 )
6882
+ {
6883
+ div.style.left = margin + "px";
6884
+ }
6885
+ else if( window.innerWidth - rect.right < 0 )
6886
+ {
6458
6887
  div.style.left = (window.innerWidth - width - margin) + "px";
6459
-
6460
- if(rect.top + rect.height > window.innerHeight)
6888
+ }
6889
+
6890
+ if( rect.top < 0 )
6891
+ {
6892
+ div.style.top = margin + "px";
6893
+ }
6894
+ else if( (rect.top + rect.height) > window.innerHeight )
6895
+ {
6461
6896
  div.style.top = (window.innerHeight - rect.height - margin) + "px";
6897
+ }
6462
6898
  }
6463
6899
  else
6464
6900
  {
6465
6901
  let dt = window.innerWidth - rect.right;
6466
- if(dt < 0) {
6902
+ if( dt < 0 )
6903
+ {
6467
6904
  div.style.left = div.offsetLeft + (dt - margin) + "px";
6468
6905
  }
6469
6906
 
6470
6907
  dt = window.innerHeight - (rect.top + rect.height);
6471
- if(dt < 0) {
6908
+ if( dt < 0 )
6909
+ {
6472
6910
  div.style.top = div.offsetTop + (dt - margin + 20 ) + "px";
6473
6911
  }
6474
6912
  }