lexgui 0.1.35 → 0.1.36

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.35",
11
+ version: "0.1.36",
12
12
  ready: false,
13
13
  components: [], // specific pre-build components
14
14
  signals: {} // events and triggers
@@ -41,43 +41,43 @@ function has( component_name )
41
41
 
42
42
  LX.has = has;
43
43
 
44
- function getExtension(s)
44
+ function getExtension( s )
45
45
  {
46
46
  return s.includes('.') ? s.split('.').pop() : null;
47
47
  }
48
48
 
49
49
  LX.getExtension = getExtension;
50
50
 
51
- function deepCopy(o)
51
+ function deepCopy( o )
52
52
  {
53
53
  return JSON.parse(JSON.stringify(o))
54
54
  }
55
55
 
56
56
  LX.deepCopy = deepCopy;
57
57
 
58
- function setThemeColor(color_name, color)
58
+ function setThemeColor( colorName, color )
59
59
  {
60
- var r = document.querySelector(':root');
61
- r.style.setProperty("--" + color_name, color);
60
+ var r = document.querySelector( ':root' );
61
+ r.style.setProperty( '--' + colorName, color );
62
62
  }
63
63
 
64
64
  LX.setThemeColor = setThemeColor;
65
65
 
66
- function getThemeColor(color_name)
66
+ function getThemeColor( colorName )
67
67
  {
68
- var r = getComputedStyle(document.querySelector(':root'));
69
- return r.getPropertyValue("--" + color_name);
68
+ var r = getComputedStyle( document.querySelector( ':root' ) );
69
+ return r.getPropertyValue( '--' + colorName );
70
70
  }
71
71
 
72
72
  LX.getThemeColor = getThemeColor;
73
73
 
74
- function getBase64Image(img) {
75
- var canvas = document.createElement("canvas");
74
+ function getBase64Image( img ) {
75
+ var canvas = document.createElement( 'canvas' );
76
76
  canvas.width = img.width;
77
77
  canvas.height = img.height;
78
- var ctx = canvas.getContext("2d");
79
- ctx.drawImage(img, 0, 0);
80
- return canvas.toDataURL("image/png");
78
+ var ctx = canvas.getContext( '2d' );
79
+ ctx.drawImage( img, 0, 0 );
80
+ return canvas.toDataURL( 'image/png' );
81
81
  }
82
82
 
83
83
  LX.getBase64Image = getBase64Image;
@@ -129,22 +129,26 @@ let ASYNC_ENABLED = true;
129
129
 
130
130
  function doAsync( fn, ms ) {
131
131
  if( ASYNC_ENABLED )
132
+ {
132
133
  setTimeout( fn, ms ?? 0 );
134
+ }
133
135
  else
136
+ {
134
137
  fn();
138
+ }
135
139
  }
136
140
 
137
141
  // Math classes
138
142
 
139
143
  class vec2 {
140
144
 
141
- constructor(x, y) {
145
+ constructor( x, y ) {
142
146
  this.x = x ?? 0;
143
- this.y = y ?? (x ?? 0);
147
+ this.y = y ?? ( x ?? 0 );
144
148
  }
145
149
 
146
- get xy() { return [ this.x, this.y]; }
147
- get yx() { return [ this.y, this.x]; }
150
+ get xy() { return [ this.x, this.y ]; }
151
+ get yx() { return [ this.y, this.x ]; }
148
152
 
149
153
  set ( x, y ) { this.x = x; this.y = y; }
150
154
  add ( v, v0 = new vec2() ) { v0.set( this.x + v.x, this.y + v.y ); return v0; }
@@ -152,6 +156,11 @@ class vec2 {
152
156
  mul ( v, v0 = new vec2() ) { if( v.constructor == Number ) { v = new vec2( v ) } v0.set( this.x * v.x, this.y * v.y ); return v0; }
153
157
  div ( v, v0 = new vec2() ) { if( v.constructor == Number ) { v = new vec2( v ) } v0.set( this.x / v.x, this.y / v.y ); return v0; }
154
158
  abs ( v0 = new vec2() ) { v0.set( Math.abs( this.x ), Math.abs( this.y ) ); return v0; }
159
+ dot ( v ) { return this.x * v.x + this.y * v.y; }
160
+ len2 () { return this.dot( this ) }
161
+ len () { return Math.sqrt( this.len2() ); }
162
+ nrm ( v0 = new vec2() ) { v0.set( this.x, this.y ); return v0.mul( 1.0 / this.len(), v0 ); }
163
+ dst ( v ) { return v.sub( this ).len(); }
155
164
  };
156
165
 
157
166
  LX.vec2 = vec2;
@@ -659,16 +668,22 @@ class TreeEvent {
659
668
 
660
669
  LX.TreeEvent = TreeEvent;
661
670
 
662
- function emit( signal_name, value, target )
671
+ function emit( signalName, value, options = {} )
663
672
  {
664
- const data = LX.signals[ signal_name ];
673
+ const data = LX.signals[ signalName ];
665
674
 
666
675
  if( !data )
667
676
  return;
668
677
 
678
+ const target = options.target;
679
+
669
680
  if( target )
670
681
  {
671
- if(target[signal_name]) target[signal_name].call(target, value);
682
+ if( target[ signalName ])
683
+ {
684
+ target[ signalName ].call( target, value );
685
+ }
686
+
672
687
  return;
673
688
  }
674
689
 
@@ -676,13 +691,16 @@ function emit( signal_name, value, target )
676
691
  {
677
692
  if( obj.constructor === Widget )
678
693
  {
679
- obj.set( value );
694
+ obj.set( value, options.skipCallback ?? true );
680
695
 
681
- if(obj.options && obj.options.callback)
682
- obj.options.callback(value, data);
683
- }else
696
+ if( obj.options && obj.options.callback )
697
+ {
698
+ obj.options.callback( value, data );
699
+ }
700
+ }
701
+ else
684
702
  {
685
- obj[signal_name].call(obj, value);
703
+ obj[ signalName ].call( obj, value );
686
704
  }
687
705
  }
688
706
  }
@@ -722,12 +740,16 @@ class Area {
722
740
 
723
741
  constructor( options = {} ) {
724
742
 
725
- var root = document.createElement('div');
743
+ var root = document.createElement( 'div' );
726
744
  root.className = "lexarea";
727
- if(options.id)
745
+ if( options.id )
746
+ {
728
747
  root.id = options.id;
729
- if(options.className)
748
+ }
749
+ if( options.className )
750
+ {
730
751
  root.className += " " + options.className;
752
+ }
731
753
 
732
754
  var width = options.width || "calc( 100% )";
733
755
  var height = options.height || "100%";
@@ -735,10 +757,14 @@ class Area {
735
757
  // This has default options..
736
758
  this.setLimitBox( options.minWidth, options.minHeight, options.maxWidth, options.maxHeight );
737
759
 
738
- if(width.constructor == Number)
760
+ if( width.constructor == Number )
761
+ {
739
762
  width += "px";
740
- if(height.constructor == Number)
763
+ }
764
+ if( height.constructor == Number )
765
+ {
741
766
  height += "px";
767
+ }
742
768
 
743
769
  root.style.width = width;
744
770
  root.style.height = height;
@@ -749,27 +775,32 @@ class Area {
749
775
  this.sections = [];
750
776
  this.panels = [];
751
777
 
752
- if(!options.no_append) {
778
+ if( !options.no_append )
779
+ {
753
780
  var lexroot = document.getElementById("lexroot");
754
781
  lexroot.appendChild( this.root );
755
782
  }
756
783
 
757
784
  let overlay = options.overlay;
758
785
 
759
- if(overlay)
786
+ if( overlay )
760
787
  {
761
788
  this.root.classList.add("overlay-" + overlay);
762
789
 
763
- if(options.left) {
790
+ if( options.left )
791
+ {
764
792
  this.root.style.left = options.left;
765
793
  }
766
- if(options.right) {
794
+ else if( options.right )
795
+ {
767
796
  this.root.style.right = options.right;
768
797
  }
769
- if(options.top) {
798
+ else if( options.top )
799
+ {
770
800
  this.root.style.top = options.top;
771
801
  }
772
- if(options.bottom) {
802
+ else if( options.bottom )
803
+ {
773
804
  this.root.style.bottom = options.bottom;
774
805
  }
775
806
 
@@ -781,97 +812,99 @@ class Area {
781
812
  root.classList.add("resizeable");
782
813
  }
783
814
 
784
- if(options.resize)
815
+ if( options.resize )
785
816
  {
786
817
  this.split_bar = document.createElement("div");
787
- let type = overlay == "left" || overlay == "right" ? "horizontal" : "vertical";
818
+ let type = (overlay == "left") || (overlay == "right") ? "horizontal" : "vertical";
788
819
  this.type = overlay;;
789
820
  this.split_bar.className = "lexsplitbar " + type;
790
- if(overlay == "right") {
821
+
822
+ if( overlay == "right" )
823
+ {
791
824
  this.split_bar.style.width = LX.DEFAULT_SPLITBAR_SIZE + "px";
792
- this.split_bar.style.left = -LX.DEFAULT_SPLITBAR_SIZE/2 + "px";
825
+ this.split_bar.style.left = -(LX.DEFAULT_SPLITBAR_SIZE / 2.0) + "px";
793
826
  }
794
- else if(overlay == "left") {
827
+ else if( overlay == "left" )
828
+ {
795
829
  let size = Math.min(document.body.clientWidth - LX.DEFAULT_SPLITBAR_SIZE, this.root.clientWidth);
796
830
  this.split_bar.style.width = LX.DEFAULT_SPLITBAR_SIZE + "px";
797
- this.split_bar.style.left = size + LX.DEFAULT_SPLITBAR_SIZE/2 + "px";
831
+ this.split_bar.style.left = size + (LX.DEFAULT_SPLITBAR_SIZE / 2.0) + "px";
798
832
  }
799
- else if (overlay == "top") {
833
+ else if( overlay == "top" )
834
+ {
800
835
  let size = Math.min(document.body.clientHeight - LX.DEFAULT_SPLITBAR_SIZE, this.root.clientHeight);
801
836
  this.split_bar.style.height = LX.DEFAULT_SPLITBAR_SIZE + "px";
802
- this.split_bar.style.top = size + LX.DEFAULT_SPLITBAR_SIZE/2 + "px";
837
+ this.split_bar.style.top = size + (LX.DEFAULT_SPLITBAR_SIZE / 2.0) + "px";
803
838
  }
804
- else if(overlay == "bottom") {
839
+ else if( overlay == "bottom" )
840
+ {
805
841
  this.split_bar.style.height = LX.DEFAULT_SPLITBAR_SIZE + "px";
806
- this.split_bar.style.top = -LX.DEFAULT_SPLITBAR_SIZE/2 + "px";
842
+ this.split_bar.style.top = -(LX.DEFAULT_SPLITBAR_SIZE / 2.0) + "px";
807
843
  }
808
844
 
809
845
  this.split_bar.addEventListener("mousedown", inner_mousedown);
810
- this.root.appendChild(this.split_bar);
846
+ this.root.appendChild( this.split_bar );
811
847
 
812
848
  var that = this;
813
- var last_pos = [0,0];
849
+ var last_pos = [ 0, 0 ];
814
850
 
815
- function inner_mousedown(e)
851
+ function inner_mousedown( e )
816
852
  {
817
853
  var doc = that.root.ownerDocument;
818
- doc.addEventListener("mousemove",inner_mousemove);
819
- doc.addEventListener("mouseup",inner_mouseup);
820
- last_pos[0] = e.x;
821
- last_pos[1] = e.y;
854
+ doc.addEventListener( 'mousemove', inner_mousemove );
855
+ doc.addEventListener( 'mouseup', inner_mouseup );
856
+ last_pos[ 0 ] = e.x;
857
+ last_pos[ 1 ] = e.y;
822
858
  e.stopPropagation();
823
859
  e.preventDefault();
824
- document.body.classList.add("nocursor");
825
- that.split_bar.classList.add("nocursor");
860
+ document.body.classList.add( 'nocursor' );
861
+ that.split_bar.classList.add( 'nocursor' );
826
862
  }
827
863
 
828
- function inner_mousemove(e)
864
+ function inner_mousemove( e )
829
865
  {
830
- switch(that.type) {
866
+ switch( that.type ) {
831
867
  case "right":
832
- var dt = (last_pos[0] - e.x);
833
- var size = (that.root.offsetWidth + dt);
868
+ var dt = ( last_pos[ 0 ] - e.x );
869
+ var size = ( that.root.offsetWidth + dt );
834
870
  that.root.style.width = size + "px";
835
871
  break;
836
-
837
872
  case "left":
838
- var dt = (last_pos[0] - e.x);
873
+ var dt = ( last_pos[ 0 ] - e.x );
839
874
  var size = Math.min(document.body.clientWidth - LX.DEFAULT_SPLITBAR_SIZE, (that.root.offsetWidth - dt));
840
875
  that.root.style.width = size + "px";
841
876
  that.split_bar.style.left = size + LX.DEFAULT_SPLITBAR_SIZE/2 + "px";
842
877
  break;
843
-
844
878
  case "top":
845
- var dt = (last_pos[1] - e.y);
879
+ var dt = ( last_pos[ 1 ] - e.y );
846
880
  var size = Math.min(document.body.clientHeight - LX.DEFAULT_SPLITBAR_SIZE, (that.root.offsetHeight - dt));
847
881
  that.root.style.height = size + "px";
848
882
  that.split_bar.style.top = size + LX.DEFAULT_SPLITBAR_SIZE/2 + "px";
849
883
  break;
850
-
851
884
  case "bottom":
852
- var dt = (last_pos[1] - e.y);
853
- var size = (that.root.offsetHeight + dt);
885
+ var dt = ( last_pos[ 1 ] - e.y );
886
+ var size = ( that.root.offsetHeight + dt );
854
887
  that.root.style.height = size + "px";
855
888
  break;
856
889
  }
857
890
 
858
- last_pos[0] = e.x;
859
- last_pos[1] = e.y;
891
+ last_pos[ 0 ] = e.x;
892
+ last_pos[ 1 ] = e.y;
860
893
  e.stopPropagation();
861
894
  e.preventDefault();
862
895
 
863
896
  // Resize events
864
- if(that.onresize)
897
+ if( that.onresize )
865
898
  that.onresize( that.root.getBoundingClientRect() );
866
899
  }
867
900
 
868
- function inner_mouseup(e)
901
+ function inner_mouseup( e )
869
902
  {
870
903
  var doc = that.root.ownerDocument;
871
- doc.removeEventListener("mousemove",inner_mousemove);
872
- doc.removeEventListener("mouseup",inner_mouseup);
873
- document.body.classList.remove("nocursor");
874
- that.split_bar.classList.remove("nocursor");
904
+ doc.removeEventListener( 'mousemove', inner_mousemove );
905
+ doc.removeEventListener( 'mouseup', inner_mouseup );
906
+ document.body.classList.remove( 'nocursor' );
907
+ that.split_bar.classList.remove( 'nocursor' );
875
908
  }
876
909
  }
877
910
  }
@@ -1154,7 +1187,7 @@ class Area {
1154
1187
  this.propagateEvent("onresize");
1155
1188
  }
1156
1189
 
1157
- /**
1190
+ /**
1158
1191
  * @method extend
1159
1192
  * Hide 2nd area split
1160
1193
  */
@@ -1603,7 +1636,7 @@ class Tabs {
1603
1636
  this.classList.remove("dockingtab");
1604
1637
 
1605
1638
  // Change tabs instance
1606
- LX.emit( "@on_tab_docked", el.instance );
1639
+ LX.emit( "@on_tab_docked" );
1607
1640
  el.instance = that;
1608
1641
 
1609
1642
  // Show on drop
@@ -1675,22 +1708,26 @@ class Tabs {
1675
1708
 
1676
1709
  let isSelected = options.selected ?? false;
1677
1710
 
1678
- if( isSelected ) {
1679
- this.root.querySelectorAll('span').forEach( s => s.classList.remove('selected'));
1680
- this.area.root.querySelectorAll('.lextabcontent').forEach( c => c.style.display = 'none');
1711
+ if( isSelected )
1712
+ {
1713
+ this.root.querySelectorAll( 'span' ).forEach( s => s.classList.remove( 'selected' ) );
1714
+ this.area.root.querySelectorAll( '.lextabcontent' ).forEach( c => c.style.display = 'none' );
1681
1715
  }
1682
1716
 
1683
1717
  isSelected = !Object.keys( this.tabs ).length && !this.folding ? true : isSelected;
1684
1718
 
1685
1719
  let contentEl = content.root ? content.root : content;
1686
- contentEl.style.display = isSelected ? "block" : "none";
1687
- contentEl.classList.add("lextabcontent");
1720
+ contentEl.originalDisplay = contentEl.style.display;
1721
+ contentEl.style.display = isSelected ? contentEl.originalDisplay : "none";
1722
+ contentEl.classList.add( 'lextabcontent' );
1688
1723
 
1689
1724
  // Process icon
1690
1725
  if( options.icon )
1691
1726
  {
1692
1727
  if( options.icon.includes( 'fa-' ) ) // It's fontawesome icon...
1728
+ {
1693
1729
  options.icon = "<i class='" + options.icon + "'></i>";
1730
+ }
1694
1731
  else // an image..
1695
1732
  {
1696
1733
  const rootPath = "https://raw.githubusercontent.com/jxarco/lexgui.js/master/";
@@ -1699,26 +1736,31 @@ class Tabs {
1699
1736
  }
1700
1737
 
1701
1738
  // Create tab
1702
- let tabEl = document.createElement('span');
1703
- tabEl.dataset["name"] = name;
1704
- tabEl.className = "lexareatab" + (isSelected ? " selected" : "");
1705
- tabEl.innerHTML = (options.icon ?? "") + name;
1706
- tabEl.id = name.replace(/\s/g, '') + Tabs.TAB_ID++;
1739
+ let tabEl = document.createElement( 'span' );
1740
+ tabEl.dataset[ "name" ] = name;
1741
+ tabEl.className = "lexareatab" + ( isSelected ? " selected" : "" );
1742
+ tabEl.innerHTML = ( options.icon ?? "" ) + name;
1743
+ tabEl.id = name.replace( /\s/g, '' ) + Tabs.TAB_ID++;
1707
1744
  tabEl.title = options.title;
1708
1745
  tabEl.selected = isSelected ?? false;
1709
1746
  tabEl.fixed = options.fixed;
1710
- if(tabEl.selected)
1711
- this.selected = name;
1712
1747
  tabEl.instance = this;
1713
1748
  contentEl.id = tabEl.id + "_content";
1714
1749
 
1750
+ if( tabEl.selected )
1751
+ {
1752
+ this.selected = name;
1753
+ }
1754
+
1715
1755
  LX.addSignal( "@on_tab_docked", tabEl, function() {
1716
- if( this.parentElement.childNodes.length == 1 ){
1717
- this.parentElement.childNodes[0].click(); // single tab!!
1756
+ if( this.parentElement.childNodes.length == 1 )
1757
+ {
1758
+ this.parentElement.childNodes[ 0 ].click(); // single tab!!
1718
1759
  }
1719
1760
  } );
1720
1761
 
1721
1762
  tabEl.addEventListener("click", e => {
1763
+
1722
1764
  e.preventDefault();
1723
1765
  e.stopPropagation();
1724
1766
 
@@ -1726,25 +1768,27 @@ class Tabs {
1726
1768
  {
1727
1769
  // For folding tabs
1728
1770
  const lastValue = tabEl.selected;
1729
- tabEl.parentElement.querySelectorAll('span').forEach( s => s.selected = false );
1771
+ tabEl.parentElement.querySelectorAll( 'span' ).forEach( s => s.selected = false );
1730
1772
  tabEl.selected = !lastValue;
1731
1773
  // Manage selected
1732
- tabEl.parentElement.querySelectorAll('span').forEach( s => s.classList.remove('selected'));
1733
- tabEl.classList.toggle('selected', (this.folding && tabEl.selected));
1774
+ tabEl.parentElement.querySelectorAll( 'span' ).forEach( s => s.classList.remove( 'selected' ));
1775
+ tabEl.classList.toggle('selected', ( this.folding && tabEl.selected ));
1734
1776
  // Manage visibility
1735
- tabEl.instance.area.root.querySelectorAll('.lextabcontent').forEach( c => c.style.display = 'none');
1736
- contentEl.style.display = "block";
1777
+ tabEl.instance.area.root.querySelectorAll( '.lextabcontent' ).forEach( c => c.style.display = 'none' );
1778
+ contentEl.style.display = contentEl.originalDisplay;
1737
1779
  tabEl.instance.selected = tabEl.dataset.name;
1738
1780
  }
1739
1781
 
1740
1782
  if( this.folding )
1741
1783
  {
1742
1784
  this.folded = tabEl.selected;
1743
- this.area.root.classList.toggle('folded', !this.folded);
1785
+ this.area.root.classList.toggle( 'folded', !this.folded );
1744
1786
  }
1745
1787
 
1746
- if(options.onSelect)
1788
+ if( options.onSelect )
1789
+ {
1747
1790
  options.onSelect(e, tabEl.dataset.name);
1791
+ }
1748
1792
 
1749
1793
  if( this.thumb )
1750
1794
  {
@@ -1759,25 +1803,28 @@ class Tabs {
1759
1803
  e.preventDefault();
1760
1804
  e.stopPropagation();
1761
1805
 
1762
- if(options.onContextMenu)
1806
+ if( options.onContextMenu )
1807
+ {
1763
1808
  options.onContextMenu( e, tabEl.dataset.name );
1809
+ }
1764
1810
  });
1765
1811
 
1766
1812
  tabEl.addEventListener("mouseup", e => {
1767
1813
  e.preventDefault();
1768
1814
  e.stopPropagation();
1769
- if( e.button == 1 ) {
1770
- this.delete( tabEl.dataset["name"] );
1815
+ if( e.button == 1 )
1816
+ {
1817
+ this.delete( tabEl.dataset[ "name" ] );
1771
1818
  }
1772
1819
  });
1773
1820
 
1774
- tabEl.setAttribute('draggable', true);
1775
- tabEl.addEventListener("dragstart", function(e) {
1821
+ tabEl.setAttribute( 'draggable', true );
1822
+ tabEl.addEventListener( 'dragstart', function( e ) {
1776
1823
  if( this.parentElement.childNodes.length == 1 ){
1777
1824
  e.preventDefault();
1778
1825
  return;
1779
1826
  }
1780
- e.dataTransfer.setData( "source", e.target.id );
1827
+ e.dataTransfer.setData( 'source', e.target.id );
1781
1828
  });
1782
1829
 
1783
1830
  // Attach content
@@ -2423,7 +2470,7 @@ class Widget {
2423
2470
  console.warn("Can't get value of " + this.typeName());
2424
2471
  }
2425
2472
 
2426
- set( value, skipCallback = false ) {
2473
+ set( value, skipCallback = false, signalName = "" ) {
2427
2474
 
2428
2475
  if( this.onSetValue )
2429
2476
  return this.onSetValue( value, skipCallback );
@@ -2485,8 +2532,7 @@ class Widget {
2485
2532
  }
2486
2533
 
2487
2534
  refresh() {
2488
- // this.domEl.innerHTML = "";
2489
- // if( this.options.callback ) this.options.callback();
2535
+
2490
2536
  }
2491
2537
  }
2492
2538
 
@@ -3788,6 +3834,8 @@ class Panel {
3788
3834
  * placeholder: Add input placeholder
3789
3835
  * trigger: Choose onchange trigger (default, input) [default]
3790
3836
  * inputWidth: Width of the text input
3837
+ * float: Justify input text content
3838
+ * justifyName: Justify name content
3791
3839
  * fitHeight: Height adapts to text
3792
3840
  */
3793
3841
 
@@ -3825,6 +3873,7 @@ class Panel {
3825
3873
  let wValue = document.createElement( 'textarea' );
3826
3874
  wValue.value = wValue.iValue = value || "";
3827
3875
  wValue.style.width = "100%";
3876
+ wValue.style.textAlign = options.float ?? "";
3828
3877
  Object.assign( wValue.style, options.style ?? {} );
3829
3878
 
3830
3879
  if( options.disabled ?? false ) wValue.setAttribute("disabled", true);
@@ -3901,8 +3950,9 @@ class Panel {
3901
3950
  * @param {String} value Button name
3902
3951
  * @param {Function} callback Callback function on click
3903
3952
  * @param {*} options:
3904
- * icon
3905
3953
  * disabled: Make the widget disabled [false]
3954
+ * icon: Icon class to show as button value
3955
+ * img: Path to image to show as button value
3906
3956
  */
3907
3957
 
3908
3958
  addButton( name, value, callback, options = {} ) {
@@ -4521,6 +4571,7 @@ class Panel {
4521
4571
  * @param {Array} values By default values in the array
4522
4572
  * @param {Function} callback Callback function on change
4523
4573
  * @param {*} options:
4574
+ * innerValues (Array): Use dropdown mode and use values as options
4524
4575
  */
4525
4576
 
4526
4577
  addArray( name, values = [], callback, options = {} ) {
@@ -5442,9 +5493,9 @@ class Panel {
5442
5493
  * @param {*} options:
5443
5494
  * min, max: Min and Max values
5444
5495
  * low, optimum, high: Low and High boundary values, Optimum point in the range
5445
- * showValue: show current value
5446
- * editable: allow edit value
5447
- * callback: function called on change value
5496
+ * showValue: Show current value
5497
+ * editable: Allow edit value
5498
+ * callback: Function called on change value
5448
5499
  */
5449
5500
 
5450
5501
  addProgress( name, value, options = {} ) {
@@ -5703,64 +5754,93 @@ class Panel {
5703
5754
 
5704
5755
  /**
5705
5756
  * @method addTabs
5706
- * @param {Array} tabs Contains objects with {name, icon, callback}
5757
+ * @param {Array} tabs Contains objects with {
5758
+ * name: Name of the tab (if icon, use as title)
5759
+ * icon: Icon to be used as the tab icon (optional)
5760
+ * onCreate: Func to be called at tab creation
5761
+ * onSelect: Func to be called on select tab (optional)
5762
+ * }
5707
5763
  * @param {*} options
5708
5764
  * vertical: Use vertical or horizontal tabs (vertical by default)
5709
5765
  * showNames: Show tab name only in horizontal tabs
5710
5766
  */
5711
5767
 
5712
5768
  addTabs( tabs, options = {} ) {
5769
+
5713
5770
  let root = this.current_branch ? this.current_branch.content : this.root;
5714
- if(!this.current_branch)
5771
+
5772
+ if( !this.current_branch )
5773
+ {
5715
5774
  console.warn("No current branch!");
5775
+ }
5716
5776
 
5717
- if(tabs.constructor != Array)
5718
- throw("Param @tabs must be an Array!");
5777
+ if( tabs.constructor != Array )
5778
+ {
5779
+ throw( "Param @tabs must be an Array!" );
5780
+ }
5719
5781
 
5720
5782
  const vertical = options.vertical ?? true;
5721
- const showNames = !vertical && (options.showNames ?? false);
5783
+ const showNames = !vertical && ( options.showNames ?? false );
5722
5784
 
5723
- let container = document.createElement('div');
5785
+ let container = document.createElement( 'div' );
5724
5786
  container.className = "lextabscontainer";
5725
- if( !vertical ) container.className += " horizontal";
5787
+ if( !vertical )
5788
+ {
5789
+ container.className += " horizontal";
5790
+ }
5726
5791
 
5727
- let tabContainer = document.createElement("div");
5728
- tabContainer.className = "tabs";
5792
+ let tabContainer = document.createElement( 'div' );
5793
+ tabContainer.className = 'tabs';
5729
5794
  container.appendChild( tabContainer );
5730
5795
  root.appendChild( container );
5731
5796
 
5732
- for( var i = 0; i < tabs.length; ++i )
5797
+ for( let i = 0; i < tabs.length; ++i )
5733
5798
  {
5734
- const tab = tabs[i];
5735
- const selected = i == 0;
5736
- let tabEl = document.createElement('div');
5737
- tabEl.className = "lextab " + (i == tabs.length - 1 ? "last" : "") + (selected ? "selected" : "");
5738
- tabEl.innerHTML = (showNames ? tab.name : "") + "<a class='" + (tab.icon || "fa fa-hashtag") + " " + (showNames ? "withname" : "") + "'></a>";
5799
+ const tab = tabs[ i ];
5800
+ console.assert( tab.name );
5801
+ const isSelected = ( i == 0 );
5802
+ let tabEl = document.createElement( 'div' );
5803
+ tabEl.className = "lextab " + (i == tabs.length - 1 ? "last" : "") + ( isSelected ? "selected" : "" );
5804
+ tabEl.innerHTML = ( showNames ? tab.name : "" ) + "<a class='" + ( tab.icon || "fa fa-hashtag" ) + " " + (showNames ? "withname" : "") + "'></a>";
5739
5805
  tabEl.title = tab.name;
5740
5806
 
5741
- let infoContainer = document.createElement("div");
5742
- infoContainer.id = tab.name.replace(/\s/g, '');
5807
+ let infoContainer = document.createElement( 'div' );
5808
+ infoContainer.id = tab.name.replace( /\s/g, '' );
5743
5809
  infoContainer.className = "widgets";
5744
- if(!selected) infoContainer.toggleAttribute('hidden', true);
5810
+
5811
+ if(!isSelected)
5812
+ {
5813
+ infoContainer.toggleAttribute('hidden', true);
5814
+ }
5815
+
5745
5816
  container.appendChild( infoContainer );
5746
5817
 
5747
- tabEl.addEventListener("click", function() {
5748
- // change selected tab
5749
- tabContainer.querySelectorAll(".lextab").forEach( e => { e.classList.remove("selected"); } );
5750
- this.classList.add("selected");
5751
- // hide all tabs content
5752
- container.querySelectorAll(".widgets").forEach( e => { e.toggleAttribute('hidden', true); } );
5753
- // show tab content
5754
- const el = container.querySelector("#" + infoContainer.id);
5755
- el.toggleAttribute('hidden');
5818
+ tabEl.addEventListener( 'click', e => {
5819
+
5820
+ // Change selected tab
5821
+ tabContainer.querySelectorAll( '.lextab' ).forEach( e => { e.classList.remove( 'selected' ); } );
5822
+ e.target.classList.add( 'selected' );
5823
+ // Hide all tabs content
5824
+ container.querySelectorAll(".widgets").forEach( e => { e.toggleAttribute( 'hidden', true ); } );
5825
+ // Show tab content
5826
+ const el = container.querySelector( '#' + infoContainer.id );
5827
+ el.toggleAttribute( 'hidden' );
5828
+
5829
+ if( tab.onSelect )
5830
+ {
5831
+ tab.onSelect( this, infoContainer );
5832
+ }
5756
5833
  });
5757
5834
 
5758
- tabContainer.appendChild(tabEl);
5835
+ tabContainer.appendChild( tabEl );
5759
5836
 
5760
- // push to tab space
5761
- this.queue( infoContainer );
5762
- tab.callback( this, infoContainer );
5763
- this.clearQueue();
5837
+ if( tab.onCreate )
5838
+ {
5839
+ // push to tab space
5840
+ this.queue( infoContainer );
5841
+ tab.onCreate( this, infoContainer );
5842
+ this.clearQueue();
5843
+ }
5764
5844
  }
5765
5845
 
5766
5846
  this.addSeparator();
@@ -5776,14 +5856,19 @@ LX.Panel = Panel;
5776
5856
  class Branch {
5777
5857
 
5778
5858
  constructor( name, options = {} ) {
5859
+
5779
5860
  this.name = name;
5780
5861
 
5781
- var root = document.createElement('div');
5862
+ var root = document.createElement( 'div' );
5782
5863
  root.className = "lexbranch";
5783
- if(options.id)
5864
+ if( options.id )
5865
+ {
5784
5866
  root.id = options.id;
5785
- if(options.className)
5867
+ }
5868
+ if( options.className )
5869
+ {
5786
5870
  root.className += " " + options.className;
5871
+ }
5787
5872
 
5788
5873
  root.style.width = "calc(100% - 7px)";
5789
5874
  root.style.margin = "0 auto";
@@ -5794,52 +5879,56 @@ class Branch {
5794
5879
  this.widgets = [];
5795
5880
 
5796
5881
  // create element
5797
- var title = document.createElement('div');
5882
+ var title = document.createElement( 'div' );
5798
5883
  title.className = "lexbranchtitle";
5799
5884
 
5800
5885
  title.innerHTML = "<a class='fa-solid fa-angle-up switch-branch-button'></a>";
5801
- if(options.icon) {
5886
+ if( options.icon )
5887
+ {
5802
5888
  title.innerHTML += "<a class='branchicon " + options.icon + "' style='margin-right: 8px; margin-bottom: -2px;'>";
5803
5889
  }
5804
5890
  title.innerHTML += name || "Branch";
5805
5891
 
5806
- root.appendChild(title);
5892
+ root.appendChild( title );
5807
5893
 
5808
- var branch_content = document.createElement('div');
5809
- branch_content.id = name.replace(/\s/g, '');
5810
- branch_content.className = "lexbranchcontent";
5811
- root.appendChild(branch_content);
5812
- this.content = branch_content;
5894
+ var branchContent = document.createElement( 'div' );
5895
+ branchContent.id = name.replace(/\s/g, '');
5896
+ branchContent.className = "lexbranchcontent";
5897
+ root.appendChild(branchContent);
5898
+ this.content = branchContent;
5813
5899
 
5814
5900
  this._addBranchSeparator();
5815
5901
 
5816
- if( options.closed ) {
5902
+ if( options.closed )
5903
+ {
5817
5904
  title.className += " closed";
5818
5905
  root.className += " closed";
5819
5906
  this.grabber.setAttribute('hidden', true);
5820
5907
  doAsync( () => {
5821
- this.content.setAttribute('hidden', true);
5822
- }, 15);
5908
+ this.content.setAttribute( 'hidden', true );
5909
+ }, 15 );
5823
5910
  }
5824
5911
 
5825
- this.onclick = function(e){
5912
+ this.onclick = function( e ) {
5826
5913
  e.stopPropagation();
5827
- this.classList.toggle('closed');
5828
- this.parentElement.classList.toggle('closed');
5914
+ this.classList.toggle( 'closed' );
5915
+ this.parentElement.classList.toggle( 'closed' );
5829
5916
 
5830
- that.content.toggleAttribute('hidden');
5831
- that.grabber.toggleAttribute('hidden');
5917
+ that.content.toggleAttribute( 'hidden' );
5918
+ that.grabber.toggleAttribute( 'hidden' );
5832
5919
 
5833
- LX.emit("@on_branch_closed", this.classList.contains("closed"), that.panel);
5920
+ LX.emit( "@on_branch_closed", this.classList.contains("closed"), { target: that.panel } );
5834
5921
  };
5835
5922
 
5836
- this.oncontextmenu = function(e) {
5923
+ this.oncontextmenu = function( e ) {
5837
5924
 
5838
5925
  e.preventDefault();
5839
5926
  e.stopPropagation();
5840
5927
 
5841
5928
  if( this.parentElement.classList.contains("dialog") )
5929
+ {
5842
5930
  return;
5931
+ }
5843
5932
 
5844
5933
  addContextMenu("Dock", e, p => {
5845
5934
  e.preventDefault();
@@ -5847,12 +5936,12 @@ class Branch {
5847
5936
  // p.add('<i class="fa-regular fa-window-maximize fa-rotate-180">', {id: 'dock_options1'});
5848
5937
  // p.add('<i class="fa-regular fa-window-maximize fa-rotate-90">', {id: 'dock_options2'});
5849
5938
  // p.add('<i class="fa-regular fa-window-maximize fa-rotate-270">', {id: 'dock_options3'});
5850
- p.add('Floating', that._on_make_floating.bind(that));
5939
+ p.add( 'Floating', that._on_make_floating.bind( that ) );
5851
5940
  }, { icon: "fa-regular fa-window-restore" });
5852
5941
  };
5853
5942
 
5854
- title.addEventListener("click", this.onclick);
5855
- title.addEventListener("contextmenu", this.oncontextmenu);
5943
+ title.addEventListener( 'click', this.onclick );
5944
+ title.addEventListener( 'contextmenu', this.oncontextmenu );
5856
5945
  }
5857
5946
 
5858
5947
  _on_make_floating() {
@@ -6867,7 +6956,6 @@ class Curve {
6867
6956
  }
6868
6957
 
6869
6958
  redraw( options = {} ) {
6870
- console.log("REDRAW!!");
6871
6959
  this.element.redraw( options );
6872
6960
  }
6873
6961
  }