lexgui 0.5.11 → 0.6.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -60,7 +60,7 @@ import { LX } from 'lexgui';
60
60
  import { CodeEditor } from 'lexgui/components/codeeditor.js';
61
61
 
62
62
  // Create main area
63
- let area = LX.init();
63
+ let area = await LX.init();
64
64
 
65
65
  // Create area panels
66
66
  let panel = area.addPanel();
@@ -276,7 +276,7 @@ class CodeEditor {
276
276
  this.explorer = panel.addTree( null, sceneData, {
277
277
  filter: false,
278
278
  rename: false,
279
- skip_default_icon: true,
279
+ skipDefaultIcon: true,
280
280
  onevent: (event) => {
281
281
  switch(event.type) {
282
282
  // case LX.TreeEvent.NODE_SELECTED:
@@ -317,7 +317,7 @@ class CodeEditor {
317
317
  this.base_area = area;
318
318
  this.area = new LX.Area( { className: "lexcodeeditor", height: "100%", skipAppend: true } );
319
319
 
320
- this.skipCodeInfo = options.skipInfo ?? false;
320
+ this.skipInfo = options.skipInfo ?? false;
321
321
  this.disableEdition = options.disableEdition ?? false;
322
322
 
323
323
  this.tabs = this.area.addTabs( { onclose: (name) => {
@@ -342,6 +342,18 @@ class CodeEditor {
342
342
  // Full editor
343
343
  area.root.classList.add('codebasearea');
344
344
 
345
+ const observer = new MutationObserver((e) => {
346
+ if( e[0].attributeName == "style" )
347
+ {
348
+ this.resize();
349
+ }
350
+ });
351
+
352
+ observer.observe( area.root.parentNode, {
353
+ attributes: true,
354
+ attributeFilter: ['class', 'style'],
355
+ });
356
+
345
357
  // Code area
346
358
  this.tabs.area.root.classList.add( 'codetabsarea' );
347
359
 
@@ -491,9 +503,9 @@ class CodeEditor {
491
503
 
492
504
  searchPanel.sameLine( 4 );
493
505
  searchPanel.addText( null, "", null, { placeholder: "Find" } );
494
- searchPanel.addButton( null, "up", () => this.search( null, true ), { icon: "fa fa-arrow-up" } );
495
- searchPanel.addButton( null, "down", () => this.search(), { icon: "fa fa-arrow-down" } );
496
- searchPanel.addButton( null, "x", this.hideSearchBox.bind( this ), { icon: "fa fa-xmark" } );
506
+ searchPanel.addButton( null, "up", () => this.search( null, true ), { icon: "ArrowUp" } );
507
+ searchPanel.addButton( null, "down", () => this.search(), { icon: "ArrowDown" } );
508
+ searchPanel.addButton( null, "x", this.hideSearchBox.bind( this ), { icon: "X" } );
497
509
 
498
510
  box.querySelector( 'input' ).addEventListener( 'keyup', e => {
499
511
  if( e.key == 'Escape' ) this.hideSearchBox();
@@ -671,7 +683,9 @@ class CodeEditor {
671
683
  this.cursorToPosition( cursor, deleteFromPosition );
672
684
 
673
685
  if( this.useAutoComplete )
686
+ {
674
687
  this.showAutoCompleteBox( 'foo', cursor );
688
+ }
675
689
  }
676
690
  else if( this.code.lines[ ln - 1 ] != undefined ) {
677
691
 
@@ -1217,6 +1231,12 @@ class CodeEditor {
1217
1231
  this.cursorToPosition( cursor, ( cursor.position + new_lines[ 0 ].length ) );
1218
1232
  this.processLine( lidx );
1219
1233
  }
1234
+
1235
+ this.resize( null, ( scrollWidth, scrollHeight ) => {
1236
+ var viewportSizeX = ( this.codeScroller.clientWidth + this.getScrollLeft() ) - CodeEditor.LINE_GUTTER_WIDTH; // Gutter offset
1237
+ if( ( cursor.position * this.charWidth ) >= viewportSizeX )
1238
+ this.setScrollLeft( this.code.lines[ lidx ].length * this.charWidth );
1239
+ } );
1220
1240
  }
1221
1241
 
1222
1242
  loadFile( file, options = {} ) {
@@ -1241,7 +1261,7 @@ class CodeEditor {
1241
1261
  };
1242
1262
 
1243
1263
  const ext = this.languages[ options.language ] ?. ext;
1244
- this.addExplorerItem( { 'id': name, 'skipVisibility': true, 'icon': this._getFileIcon( name, ext ) } );
1264
+ this.addExplorerItem( { id: name, skipVisibility: true, icon: this._getFileIcon( name, ext ) } );
1245
1265
  this.explorer.innerTree.frefresh( name );
1246
1266
  }
1247
1267
  else
@@ -1453,7 +1473,7 @@ class CodeEditor {
1453
1473
  }
1454
1474
  }
1455
1475
 
1456
- _changeLanguage( lang, override = false ) {
1476
+ _changeLanguage( lang, langExtension, override = false ) {
1457
1477
 
1458
1478
  this.code.language = lang;
1459
1479
  this.highlight = lang;
@@ -1466,7 +1486,7 @@ class CodeEditor {
1466
1486
  this._updateDataInfoPanel( "@highlight", lang );
1467
1487
  this.processLines();
1468
1488
 
1469
- const ext = this.languages[ lang ].ext;
1489
+ const ext = langExtension ?? this.languages[ lang ].ext;
1470
1490
  const icon = this._getFileIcon( null, ext );
1471
1491
 
1472
1492
  // Update tab icon
@@ -1475,10 +1495,10 @@ class CodeEditor {
1475
1495
  tab.firstChild.remove();
1476
1496
  console.assert( tab != undefined );
1477
1497
  var iconEl;
1478
- if( icon.includes( 'fa-' ) )
1498
+ if( !icon.includes( '.' ) ) // Not a file
1479
1499
  {
1480
- iconEl = document.createElement( 'i' );
1481
- iconEl.className = icon;
1500
+ const classes = icon.split( ' ' );
1501
+ iconEl = LX.makeIcon( classes[ 0 ], { svgClass: classes.slice( 0 ).join( ' ' ) } );
1482
1502
  } else
1483
1503
  {
1484
1504
  iconEl = document.createElement( 'img' );
@@ -1512,7 +1532,7 @@ class CodeEditor {
1512
1532
  {
1513
1533
  if( langExtension.indexOf( ext ) > -1 )
1514
1534
  {
1515
- return this._changeLanguage( l );
1535
+ return this._changeLanguage( l, ext );
1516
1536
  }
1517
1537
  }
1518
1538
  else
@@ -1530,7 +1550,7 @@ class CodeEditor {
1530
1550
 
1531
1551
  _createPanelInfo() {
1532
1552
 
1533
- if( !this.skipCodeInfo )
1553
+ if( !this.skipInfo )
1534
1554
  {
1535
1555
  let panel = new LX.Panel({ className: "lexcodetabinfo", width: "calc(100%)", height: "auto" });
1536
1556
 
@@ -1554,7 +1574,7 @@ class CodeEditor {
1554
1574
  for( const lang of Object.keys( this.languages ) )
1555
1575
  {
1556
1576
  m.add( lang, v => {
1557
- this._changeLanguage( v, true )
1577
+ this._changeLanguage( v, null, true )
1558
1578
  } );
1559
1579
  }
1560
1580
  });
@@ -1606,12 +1626,20 @@ class CodeEditor {
1606
1626
  }
1607
1627
  }
1608
1628
 
1609
- return extension == "html" ? "fa-solid fa-code orange" :
1610
- extension == "css" ? "fa-solid fa-hashtag dodgerblue" :
1611
- extension == "xml" ? "fa-solid fa-rss orange" :
1612
- extension == "bat" ? "fa-brands fa-windows lightblue" :
1613
- [ 'js', 'py', 'json', 'cpp', 'hpp', 'rs', 'md' ].indexOf( extension ) > -1 ? "images/" + extension + ".png" :
1614
- !isNewTabButton ? "fa-solid fa-align-left gray" : undefined;
1629
+ return extension == "html" ? "Code orange" :
1630
+ extension == "css" ? "Hash dodgerblue" :
1631
+ extension == "xml" ? "Rss orange" :
1632
+ extension == "bat" ? "Windows lightblue" :
1633
+ extension == "json" ? "Braces fg-primary" :
1634
+ extension == "js" ? "Js goldenrod" :
1635
+ extension == "py" ? "Python munsellblue" :
1636
+ extension == "rs" ? "Rust fg-primary" :
1637
+ extension == "md" ? "Markdown fg-primary" :
1638
+ extension == "cpp" ? "CPlusPlus pictonblue" :
1639
+ extension == "hpp" ? "CPlusPlus heliotrope" :
1640
+ extension == "c" ? "C pictonblue" :
1641
+ extension == "h" ? "C heliotrope" :
1642
+ !isNewTabButton ? "AlignLeft gray" : undefined;
1615
1643
  }
1616
1644
 
1617
1645
  _onNewTab( e ) {
@@ -1721,7 +1749,7 @@ class CodeEditor {
1721
1749
 
1722
1750
  if( this.explorer && !isNewTabButton )
1723
1751
  {
1724
- this.addExplorerItem( { 'id': name, 'skipVisibility': true, 'icon': tabIcon } );
1752
+ this.addExplorerItem( { id: name, skipVisibility: true, icon: tabIcon } );
1725
1753
  this.explorer.innerTree.frefresh( name );
1726
1754
  }
1727
1755
 
@@ -1782,7 +1810,7 @@ class CodeEditor {
1782
1810
 
1783
1811
  if( tabData.options.language )
1784
1812
  {
1785
- this._changeLanguage( tabData.options.language, true );
1813
+ this._changeLanguage( tabData.options.language, null, true );
1786
1814
  }
1787
1815
  else
1788
1816
  {
@@ -2464,14 +2492,20 @@ class CodeEditor {
2464
2492
  const numViewportChars = Math.floor( ( this.codeScroller.clientWidth - CodeEditor.LINE_GUTTER_WIDTH ) / this.charWidth );
2465
2493
  if( maxLineLength >= numViewportChars && maxLineLength != this._lastMaxLineLength )
2466
2494
  {
2467
- this.resize( maxLineLength );
2468
- this.setScrollLeft( 1e4 );
2495
+ this.resize( maxLineLength, () => {
2496
+ if( cursor.position > numViewportChars )
2497
+ {
2498
+ this.setScrollLeft( cursor.position * this.charWidth );
2499
+ }
2500
+ } );
2469
2501
  }
2470
2502
 
2471
2503
  // Manage autocomplete
2472
2504
 
2473
2505
  if( this.useAutoComplete )
2506
+ {
2474
2507
  this.showAutoCompleteBox( key, cursor );
2508
+ }
2475
2509
  }
2476
2510
 
2477
2511
  async _pasteContent( cursor ) {
@@ -2497,11 +2531,12 @@ class CodeEditor {
2497
2531
 
2498
2532
  let text_to_copy = "";
2499
2533
 
2500
- if( !cursor.selection ) {
2534
+ if( !cursor.selection )
2535
+ {
2501
2536
  text_to_copy = "\n" + this.code.lines[ cursor.line ];
2502
2537
  }
2503
- else {
2504
-
2538
+ else
2539
+ {
2505
2540
  // Some selections don't depend on mouse up..
2506
2541
  if( cursor.selection ) cursor.selection.invertIfNecessary();
2507
2542
 
@@ -2531,7 +2566,8 @@ class CodeEditor {
2531
2566
 
2532
2567
  this._addUndoStep( cursor, true );
2533
2568
 
2534
- if( !cursor.selection ) {
2569
+ if( !cursor.selection )
2570
+ {
2535
2571
  text_to_cut = "\n" + this.code.lines[ cursor.line ];
2536
2572
  this.code.lines.splice( lidx, 1 );
2537
2573
  this.processLines();
@@ -2539,8 +2575,8 @@ class CodeEditor {
2539
2575
  if( this.code.lines[ lidx ] == undefined )
2540
2576
  this.lineUp( cursor );
2541
2577
  }
2542
- else {
2543
-
2578
+ else
2579
+ {
2544
2580
  // Some selections don't depend on mouse up..
2545
2581
  if( cursor.selection ) cursor.selection.invertIfNecessary();
2546
2582
 
@@ -3735,7 +3771,7 @@ class CodeEditor {
3735
3771
  this.setScrollBarValue( 'vertical' );
3736
3772
  }
3737
3773
 
3738
- resize( pMaxLength ) {
3774
+ resize( pMaxLength, onResize ) {
3739
3775
 
3740
3776
  setTimeout( () => {
3741
3777
 
@@ -3751,6 +3787,11 @@ class CodeEditor {
3751
3787
 
3752
3788
  this.resizeScrollBars();
3753
3789
 
3790
+ if( onResize )
3791
+ {
3792
+ onResize( scrollWidth, scrollHeight );
3793
+ }
3794
+
3754
3795
  }, 10 );
3755
3796
  }
3756
3797
 
@@ -3933,7 +3974,7 @@ class CodeEditor {
3933
3974
 
3934
3975
  runScript( code ) {
3935
3976
 
3936
- var script = document.createElement( 'script' );
3977
+ const script = document.createElement( 'script' );
3937
3978
  script.type = 'module';
3938
3979
  script.innerHTML = code;
3939
3980
  // script.src = url[ i ] + ( version ? "?version=" + version : "" );
@@ -4018,16 +4059,14 @@ class CodeEditor {
4018
4059
  var pre = document.createElement( 'pre' );
4019
4060
  this.autocomplete.appendChild( pre );
4020
4061
 
4021
- var icon = document.createElement( 'a' );
4062
+ var icon = "Type";
4022
4063
 
4023
4064
  if( this._mustHightlightWord( s, CodeEditor.utils ) )
4024
- icon.className = "fa fa-cube";
4065
+ icon = "Box";
4025
4066
  else if( this._mustHightlightWord( s, CodeEditor.types ) )
4026
- icon.className = "fa fa-code";
4027
- else
4028
- icon.className = "fa fa-font";
4067
+ icon = "Code";
4029
4068
 
4030
- pre.appendChild( icon );
4069
+ pre.appendChild( LX.makeIcon( icon, { iconClass: "mr-1", svgClass: "xs" } ) );
4031
4070
 
4032
4071
  pre.addEventListener( 'click', () => {
4033
4072
  this.autoCompleteWord( s );
@@ -4078,6 +4117,8 @@ class CodeEditor {
4078
4117
  const isActive = this.isAutoCompleteActive;
4079
4118
  this.isAutoCompleteActive = false;
4080
4119
  this.autocomplete.classList.remove( 'show' );
4120
+ this.autocomplete.innerHTML = ""; // Clear all suggestions
4121
+
4081
4122
  return isActive != this.isAutoCompleteActive;
4082
4123
  }
4083
4124
 
@@ -4111,7 +4152,9 @@ class CodeEditor {
4111
4152
  _getSelectedAutoComplete() {
4112
4153
 
4113
4154
  if( !this.isAutoCompleteActive )
4114
- return;
4155
+ {
4156
+ return;
4157
+ }
4115
4158
 
4116
4159
  for( let i = 0; i < this.autocomplete.childElementCount; ++i )
4117
4160
  {
@@ -4120,7 +4163,13 @@ class CodeEditor {
4120
4163
  {
4121
4164
  var word = "";
4122
4165
  for( let childSpan of child.childNodes )
4166
+ {
4167
+ if( childSpan.constructor != HTMLSpanElement )
4168
+ {
4169
+ continue;
4170
+ }
4123
4171
  word += childSpan.innerHTML;
4172
+ }
4124
4173
 
4125
4174
  return [ word, i ]; // Get text of the span inside the 'pre' element
4126
4175
  }
@@ -4382,7 +4431,7 @@ class CodeEditor {
4382
4431
 
4383
4432
  _updateDataInfoPanel( signal, value ) {
4384
4433
 
4385
- if( !this.skipCodeInfo )
4434
+ if( !this.skipInfo )
4386
4435
  {
4387
4436
  if( this.cursors.childElementCount > 1 )
4388
4437
  {
@@ -96,11 +96,11 @@ class GraphEditor {
96
96
 
97
97
  }, {
98
98
  displaySelected: true,
99
- headerIcon: "more",
99
+ headerIcon: "EllipsisVertical",
100
100
  headerTitle: "Create",
101
101
  headerSubtitle: "Press to rename",
102
102
  onHeaderPressed: () => this._showRenameGraphDialog(),
103
- footerIcon: "plus",
103
+ footerIcon: "Plus",
104
104
  footerTitle: "Create",
105
105
  footerSubtitle: "Graph or Function",
106
106
  onFooterPressed: (e) => this._onSidebarCreate( e )
@@ -135,13 +135,13 @@ class GraphEditor {
135
135
  [
136
136
  {
137
137
  name: "Start Graph",
138
- icon: "fa fa-play",
138
+ icon: "Play@solid",
139
139
  callback: (value, event) => this.start(),
140
140
  selectable: true
141
141
  },
142
142
  {
143
143
  name: "Stop Graph",
144
- icon: "fa-solid fa-stop",
144
+ icon: "Stop@solid",
145
145
  callback: (value, event) => this.stop(),
146
146
  selectable: true
147
147
  }
@@ -149,7 +149,7 @@ class GraphEditor {
149
149
  [
150
150
  {
151
151
  name: "Enable Snapping",
152
- icon: "fa fa-table-cells",
152
+ icon: "Frame",
153
153
  callback: () => this._toggleSnapping(),
154
154
  selectable: true
155
155
  },
@@ -162,12 +162,12 @@ class GraphEditor {
162
162
  [
163
163
  {
164
164
  name: "Import",
165
- icon: "fa fa-upload",
165
+ icon: "Upload",
166
166
  callback: (value, event) => { this.loadGraph( "../../data/graph_sample.json" ); }
167
167
  },
168
168
  {
169
169
  name: "Export",
170
- icon: "fa fa-diagram-project",
170
+ icon: "ArrowRightFromLine",
171
171
  callback: (value, event) => this.currentGraph.export()
172
172
  }
173
173
  ]
@@ -478,7 +478,7 @@ class GraphEditor {
478
478
 
479
479
  this.setGraph( graph );
480
480
 
481
- this._sidebar.add( graph.name, { icon: "fa fa-diagram-project", className: graph.id, callback: (e) => { this.setGraph( graph ) } } );
481
+ this._sidebar.add( graph.name, { icon: "CircleNodes", className: graph.id, callback: (e) => { this.setGraph( graph ) } } );
482
482
 
483
483
  this._sidebar.update();
484
484
 
@@ -531,7 +531,7 @@ class GraphEditor {
531
531
  NodeFunction.gid = func.id;
532
532
  GraphEditor.registerCustomNode( "function/" + func.name, NodeFunction );
533
533
 
534
- this._sidebar.add( func.name, { icon: "fa fa-florin-sign", className: func.id, callback: (e) => { this.setGraph( func ) } } );
534
+ this._sidebar.add( func.name, { icon: "Function", className: func.id, callback: (e) => { this.setGraph( func ) } } );
535
535
 
536
536
  this._sidebar.update();
537
537
 
@@ -1907,6 +1907,7 @@ class GraphEditor {
1907
1907
  svg.classList.add( "background-svg" );
1908
1908
  svg.style.width = "100%";
1909
1909
  svg.style.height = "100%";
1910
+ svg.style.stroke = "none";
1910
1911
 
1911
1912
  svg.appendChild( pattern );
1912
1913
 
@@ -2242,7 +2243,7 @@ class GraphEditor {
2242
2243
  C ${ cPoint1.x },${ cPoint1.y } ${ cPoint2.x },${ cPoint2.y } ${ endPos.x },${ endPos.y }
2243
2244
  ` );
2244
2245
 
2245
- path.setAttribute( 'stroke', color );
2246
+ path.parentElement.style.color = color;
2246
2247
  }
2247
2248
 
2248
2249
  _updateNodeLinks( nodeId ) {
@@ -2495,15 +2496,18 @@ class GraphEditor {
2495
2496
  }
2496
2497
  }
2497
2498
 
2498
- // Add padding
2499
+ if( group_bb )
2500
+ {
2501
+ // Add padding
2499
2502
 
2500
- const groupContentPadding = 8;
2503
+ const groupContentPadding = 8;
2501
2504
 
2502
- group_bb.origin.sub( new LX.vec2( groupContentPadding ), group_bb.origin );
2503
- group_bb.origin.sub( new LX.vec2( groupContentPadding ), group_bb.origin );
2505
+ group_bb.origin.sub( new LX.vec2( groupContentPadding ), group_bb.origin );
2506
+ group_bb.origin.sub( new LX.vec2( groupContentPadding ), group_bb.origin );
2504
2507
 
2505
- group_bb.size.add( new LX.vec2( groupContentPadding * 2.0 ), group_bb.size );
2506
- group_bb.size.add( new LX.vec2( groupContentPadding * 2.0 ), group_bb.size );
2508
+ group_bb.size.add( new LX.vec2( groupContentPadding * 2.0 ), group_bb.size );
2509
+ group_bb.size.add( new LX.vec2( groupContentPadding * 2.0 ), group_bb.size );
2510
+ }
2507
2511
 
2508
2512
  return group_bb;
2509
2513
  }
@@ -2517,6 +2521,11 @@ class GraphEditor {
2517
2521
  _createGroup( bb ) {
2518
2522
 
2519
2523
  const group_bb = bb ?? this._getBoundingFromNodes( this.selectedNodes );
2524
+ if( !group_bb )
2525
+ {
2526
+ return;
2527
+ }
2528
+
2520
2529
  const group_id = bb ? bb.id : "group-" + LX.UTILS.uidGenerator();
2521
2530
 
2522
2531
  let groupDOM = document.createElement( 'div' );
@@ -2633,7 +2642,8 @@ class GraphEditor {
2633
2642
 
2634
2643
  LX.makeDraggable( groupDOM, {
2635
2644
  onMove: this._onMoveGroup.bind( this ),
2636
- onDragStart: this._onDragGroup.bind( this )
2645
+ onDragStart: this._onDragGroup.bind( this ),
2646
+ updateLayers: false
2637
2647
  } );
2638
2648
 
2639
2649
  GraphEditor.LAST_GROUP_ID++;
@@ -2725,10 +2735,10 @@ class GraphEditor {
2725
2735
 
2726
2736
  _onSidebarCreate( e ) {
2727
2737
 
2728
- LX.addContextMenu(null, e, m => {
2729
- m.add( "Graph", () => this.addGraph() );
2730
- m.add( "Function", () => this.addGraphFunction() );
2731
- });
2738
+ new LX.DropdownMenu( e.target, [
2739
+ { name: "Create Graph", icon: "Workflow", callback: () => this.addGraph() },
2740
+ { name: "Create Function", icon: "Function", callback: () => this.addGraphFunction() },
2741
+ ], { side: "right", align: "start" });
2732
2742
  }
2733
2743
 
2734
2744
  _showRenameGraphDialog() {
@@ -2757,8 +2767,7 @@ class GraphEditor {
2757
2767
  {
2758
2768
  sidebarItem.name = newNameKey;
2759
2769
  sidebarItem.dom.id = newNameKey;
2760
- sidebarItem.dom.querySelector(".lexsidebarentrydesc").innerText = name;
2761
- sidebarItem.dom.querySelector("a").innerText = name;
2770
+ sidebarItem.dom.innerHTML = sidebarItem.dom.innerHTML.replace( sidebarItem.dom.innerText, name );
2762
2771
  }
2763
2772
 
2764
2773
  // Change registered nodes function
@@ -162,7 +162,7 @@ class Timeline {
162
162
 
163
163
  const playbtn = header.addButton("playBtn", '', (value, event) => {
164
164
  this.changeState();
165
- }, { buttonClass: "accept", title: "Play", hideName: true, icon: "fa-solid fa-play", swap: "fa-solid fa-pause" });
165
+ }, { buttonClass: "accept", title: "Play", hideName: true, icon: "Play", swap: "Pause" });
166
166
  playbtn.root.setState(this.playing, true);
167
167
 
168
168
  header.addBlank("0.05em", "auto");
@@ -172,13 +172,13 @@ class Timeline {
172
172
  if ( this.onStateStop ){
173
173
  this.onStateStop();
174
174
  }
175
- }, { buttonClass: "accept", title: "Stop", hideName: true, icon: "fa-solid fa-stop" });
175
+ }, { buttonClass: "accept", title: "Stop", hideName: true, icon: "Stop" });
176
176
 
177
177
  header.addBlank("0.05em", "auto");
178
178
 
179
179
  header.addButton("loopBtn", '', ( value, event ) => {
180
180
  this.setLoopMode(!this.loop);
181
- }, { selectable: true, selected: this.loop, title: 'Loop', hideName: true, icon: "fa-solid fa-rotate" });
181
+ }, { selectable: true, selected: this.loop, title: 'Loop', hideName: true, icon: "Refresh" });
182
182
 
183
183
  if( this.onCreateControlsButtons ){
184
184
  this.onCreateControlsButtons( header );
@@ -235,7 +235,7 @@ class Timeline {
235
235
 
236
236
  if( this.onShowOptimizeMenu )
237
237
  {
238
- header.addButton(null, "", (value, event) => {this.onShowOptimizeMenu(event)}, { title: "Optimize", icon:"fa-solid fa-filter" });
238
+ header.addButton(null, "", (value, event) => {this.onShowOptimizeMenu(event)}, { title: "Optimize", icon:"Funnel" });
239
239
  }
240
240
  header.addBlank("0.05em", "auto");
241
241
 
@@ -256,7 +256,7 @@ class Timeline {
256
256
  root.remove();
257
257
  }
258
258
  })
259
- }, { title: "Settings", icon: "fa-solid fa-gear" })
259
+ }, { title: "Settings", icon: "Settings" })
260
260
  }
261
261
 
262
262
  header.clearQueue( buttonContainerEnd );
@@ -390,7 +390,7 @@ class VideoEditor {
390
390
  this.video.pause();
391
391
  }
392
392
  this.controlsPanelLeft.refresh();
393
- }, { width: '40px', icon: "fa-solid " + (this.playing ? 'fa-pause' : 'fa-play') });
393
+ }, { width: '40px', icon: (this.playing ? 'Pause' : 'Play') });
394
394
 
395
395
  this.controlsPanelLeft.addLabel(this.startTimeString, {width: 50});
396
396
  this.controlsPanelLeft.endLine();