lexgui 0.1.33 → 0.1.35

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.33",
11
+ version: "0.1.35",
12
12
  ready: false,
13
13
  components: [], // specific pre-build components
14
14
  signals: {} // events and triggers
@@ -21,8 +21,11 @@ LX.MOUSE_RIGHT_CLICK = 2;
21
21
  LX.MOUSE_DOUBLE_CLICK = 2;
22
22
  LX.MOUSE_TRIPLE_CLICK = 3;
23
23
 
24
- function clamp (num, min, max) { return Math.min(Math.max(num, min), max) }
25
- function round(num, n) { return +num.toFixed(n); }
24
+ LX.CURVE_MOVEOUT_CLAMP = 0;
25
+ LX.CURVE_MOVEOUT_DELETE = 1;
26
+
27
+ function clamp( num, min, max ) { return Math.min( Math.max( num, min ), max ); }
28
+ function round( num, n ) { return +num.toFixed( n ); }
26
29
 
27
30
  function getSupportedDOMName( string )
28
31
  {
@@ -466,7 +469,7 @@ function init( options = { } )
466
469
  var link = document.createElement( 'link' );
467
470
  link.rel = 'stylesheet';
468
471
  link.type = 'text/css';
469
- link.href = 'https://use.fontawesome.com/releases/v6.5.1/css/all.css';
472
+ link.href = 'https://use.fontawesome.com/releases/v6.6.0/css/all.css';
470
473
  head.appendChild( link );
471
474
 
472
475
  // Global vars
@@ -520,26 +523,29 @@ LX.message = message;
520
523
  * size: (Array) [width, height]
521
524
  */
522
525
 
523
- function popup(text, title, options = {})
526
+ function popup( text, title, options = {} )
524
527
  {
525
- if(!text)
528
+ if( !text )
529
+ {
526
530
  throw("No message to show");
531
+ }
527
532
 
528
- options.size = options.size ?? ["auto", "auto"];
533
+ options.size = options.size ?? [ "auto", "auto" ];
529
534
  options.class = "lexpopup";
530
- const time = options.timeout || 3000;
531
535
 
532
- const dialog = new Dialog(title, p => {
533
- p.addTextArea(null, text, null, { disabled: true, fitHeight: true });
534
- }, options);
536
+ const time = options.timeout || 3000;
537
+ const dialog = new Dialog( title, p => {
538
+ p.addTextArea( null, text, null, { disabled: true, fitHeight: true } );
539
+ }, options );
535
540
 
536
- dialog.root.classList.add("fadein");
541
+ dialog.root.classList.add( 'fadein' );
537
542
  setTimeout(() => {
538
- dialog.root.classList.remove("fadein");
539
- dialog.root.classList.add("fadeout");
540
- }, time - 1000);
543
+ dialog.root.classList.remove( 'fadein' );
544
+ dialog.root.classList.add( 'fadeout' );
545
+ }, time - 1000 );
541
546
 
542
- setTimeout(dialog.close, time);
547
+ setTimeout( dialog.close, time );
548
+
543
549
  return dialog;
544
550
  }
545
551
 
@@ -558,36 +564,45 @@ LX.popup = popup;
558
564
  * required: Input has to be filled [true]. Default: false
559
565
  */
560
566
 
561
- function prompt(text, title, callback, options = {})
567
+ function prompt( text, title, callback, options = {} )
562
568
  {
563
569
  options.modal = true;
564
570
 
565
571
  let value = "";
566
572
 
567
- const dialog = new Dialog(title, p => {
568
- p.addTextArea(null, text, null, { disabled: true });
569
- if(options.input !== false)
570
- p.addText(null, options.input || value, (v) => value = v, {placeholder: "..."} );
571
- p.sameLine(2);
572
- p.addButton(null, options.accept || "OK", () => {
573
- if(options.required && value === '') {
573
+ const dialog = new Dialog( title, p => {
574
574
 
575
- text += text.includes("You must fill the input text.") ? "": "\nYou must fill the input text.";
576
- dialog.close() ;
577
- prompt(text, title, callback, options);
578
- }else {
575
+ p.addTextArea( null, text, null, { disabled: true, fitHeight: true } );
579
576
 
580
- callback.call(this, value);
581
- dialog.close() ;
577
+ if( options.input ?? true )
578
+ {
579
+ p.addText( null, options.input || value, v => value = v, { placeholder: "..." } );
580
+ }
581
+
582
+ p.sameLine( 2 );
583
+
584
+ p.addButton( null, options.accept || "OK", () => {
585
+ if( options.required && value === '' )
586
+ {
587
+ text += text.includes("You must fill the input text.") ? "": "\nYou must fill the input text.";
588
+ dialog.close();
589
+ prompt( text, title, callback, options );
590
+ }else
591
+ {
592
+ if( callback ) callback.call( this, value );
593
+ dialog.close();
582
594
  }
583
-
584
595
  }, { buttonClass: "accept" });
596
+
585
597
  p.addButton(null, "Cancel", () => {if(options.on_cancel) options.on_cancel(); dialog.close();} );
586
- }, options);
598
+
599
+ }, options );
587
600
 
588
601
  // Focus text prompt
589
- if(options.input !== false)
590
- dialog.root.querySelector('input').focus();
602
+ if( options.input ?? true )
603
+ {
604
+ dialog.root.querySelector( 'input' ).focus();
605
+ }
591
606
 
592
607
  return dialog;
593
608
  }
@@ -624,6 +639,7 @@ class TreeEvent {
624
639
  this.node = node;
625
640
  this.value = value;
626
641
  this.multiple = false; // Multiple selection
642
+ this.panel = null;
627
643
  }
628
644
 
629
645
  string() {
@@ -892,35 +908,36 @@ class Area {
892
908
 
893
909
  split( options = {} ) {
894
910
 
895
- if(this.sections.length)
911
+ if( this.sections.length )
896
912
  {
897
913
  // In case Area has been split before, get 2nd section as root
898
- this.offset = this.root.childNodes[0].offsetHeight; // store offset to take into account when resizing
899
- this._root = this.sections[0].root;
900
- this.root = this.sections[1].root;
914
+ this.offset = this.root.childNodes[ 0 ].offsetHeight; // store offset to take into account when resizing
915
+ this._root = this.sections[ 0 ].root;
916
+ this.root = this.sections[ 1 ].root;
901
917
  }
902
918
 
903
919
  var type = options.type || "horizontal";
904
- var sizes = options.sizes || ["50%", "50%"];
920
+ var sizes = options.sizes || [ "50%", "50%" ];
905
921
  var infer_height = false;
906
- var auto = options.sizes === 'auto';
922
+ var auto = (options.sizes === 'auto');
907
923
 
908
- if( !sizes[1] )
924
+ if( !sizes[ 1 ] )
909
925
  {
910
- let size = sizes[0];
926
+ let size = sizes[ 0 ];
911
927
  let margin = options.top ? options.top : 0;
912
- if(size.constructor == Number) {
928
+ if( size.constructor == Number )
929
+ {
913
930
  size += margin;
914
931
  size += "px";
915
932
  }
916
933
 
917
- sizes[1] = "calc( 100% - " + size + " )";
934
+ sizes[ 1 ] = "calc( 100% - " + size + " )";
918
935
  infer_height = true;
919
936
  }
920
937
 
921
938
  // Create areas
922
- var area1 = new Area({ no_append: true, className: "split" + (options.menubar || options.sidebar ? "" : " origin") });
923
- var area2 = new Area({ no_append: true, className: "split"});
939
+ var area1 = new Area( { no_append: true, className: "split" + ( options.menubar || options.sidebar ? "" : " origin" ) } );
940
+ var area2 = new Area( { no_append: true, className: "split"} );
924
941
 
925
942
  area1.parentArea = this;
926
943
  area2.parentArea = this;
@@ -931,23 +948,27 @@ class Area {
931
948
  var data = "0px";
932
949
  this.offset = 0;
933
950
 
934
- if(resize)
951
+ if( resize )
935
952
  {
936
953
  this.resize = resize;
937
- this.split_bar = document.createElement("div");
954
+ this.split_bar = document.createElement( "div" );
938
955
  this.split_bar.className = "lexsplitbar " + type;
939
956
 
940
- if(type == "horizontal") {
957
+ if( type == "horizontal" )
958
+ {
941
959
  this.split_bar.style.width = LX.DEFAULT_SPLITBAR_SIZE + "px";
942
960
  }
943
- else {
961
+ else
962
+ {
944
963
  this.split_bar.style.height = LX.DEFAULT_SPLITBAR_SIZE + "px";
945
964
  }
946
- this.split_bar.addEventListener("mousedown", inner_mousedown);
947
- data = LX.DEFAULT_SPLITBAR_SIZE/2 + "px"; // updates
965
+
966
+ this.split_bar.addEventListener( 'mousedown', inner_mousedown );
967
+
968
+ data = ( LX.DEFAULT_SPLITBAR_SIZE / 2 ) + "px"; // updates
948
969
 
949
970
  // Being minimizable means it's also resizeable!
950
- if(minimizable)
971
+ if( minimizable )
951
972
  {
952
973
  this.split_extended = false;
953
974
 
@@ -969,14 +990,14 @@ class Area {
969
990
  }
970
991
  }
971
992
 
972
- if(type == "horizontal")
993
+ if( type == "horizontal" )
973
994
  {
974
- var width1 = sizes[0],
975
- width2 = sizes[1];
995
+ var width1 = sizes[ 0 ],
996
+ width2 = sizes[ 1 ];
976
997
 
977
- if(width1.constructor == Number)
998
+ if( width1.constructor == Number )
978
999
  width1 += "px";
979
- if(width2.constructor == Number)
1000
+ if( width2.constructor == Number )
980
1001
  width2 += "px";
981
1002
 
982
1003
  area1.root.style.width = "calc( " + width1 + " - " + data + " )";
@@ -995,19 +1016,19 @@ class Area {
995
1016
  area1.root.style.height = "auto";
996
1017
 
997
1018
  // Listen resize event on first area
998
- const resizeObserver = new ResizeObserver((entries) => {
1019
+ const resizeObserver = new ResizeObserver( entries => {
999
1020
  for (const entry of entries) {
1000
1021
  const bb = entry.contentRect;
1001
1022
  area2.root.style.height = "calc(100% - " + ( bb.height + 4) + "px )";
1002
1023
  }
1003
1024
  });
1004
1025
 
1005
- resizeObserver.observe(area1.root);
1026
+ resizeObserver.observe( area1.root );
1006
1027
  }
1007
1028
  else
1008
1029
  {
1009
- var height1 = sizes[0],
1010
- height2 = sizes[1];
1030
+ var height1 = sizes[ 0 ],
1031
+ height2 = sizes[ 1 ];
1011
1032
 
1012
1033
  if(height1.constructor == Number)
1013
1034
  height1 += "px";
@@ -1022,7 +1043,7 @@ class Area {
1022
1043
 
1023
1044
  this.root.appendChild( area1.root );
1024
1045
 
1025
- if(resize)
1046
+ if( resize )
1026
1047
  {
1027
1048
  this.root.appendChild(this.split_bar);
1028
1049
  }
@@ -1034,55 +1055,67 @@ class Area {
1034
1055
  // Update sizes
1035
1056
  this._update();
1036
1057
 
1037
- if(!resize)
1058
+ if( !resize )
1038
1059
  {
1039
1060
  return this.sections;
1040
1061
  }
1041
1062
 
1042
- // from litegui.js @jagenjo
1043
-
1044
1063
  var that = this;
1045
- var last_pos = [0,0];
1046
- function inner_mousedown(e)
1064
+ var last_pos = [ 0, 0 ];
1065
+
1066
+ function inner_mousedown( e )
1047
1067
  {
1048
1068
  var doc = that.root.ownerDocument;
1049
- doc.addEventListener("mousemove",inner_mousemove);
1050
- doc.addEventListener("mouseup",inner_mouseup);
1069
+ doc.addEventListener( 'mousemove', inner_mousemove );
1070
+ doc.addEventListener( 'mouseup', inner_mouseup );
1051
1071
  last_pos[0] = e.x;
1052
1072
  last_pos[1] = e.y;
1053
1073
  e.stopPropagation();
1054
1074
  e.preventDefault();
1055
- document.body.classList.add("nocursor");
1056
- that.split_bar.classList.add("nocursor");
1075
+ document.body.classList.add( 'nocursor' );
1076
+ that.split_bar.classList.add( 'nocursor' );
1057
1077
  }
1058
1078
 
1059
- function inner_mousemove(e)
1079
+ function inner_mousemove( e )
1060
1080
  {
1061
- if(that.type == "horizontal") {
1062
- that._moveSplit(last_pos[0] - e.x);
1081
+ if(that.type == "horizontal")
1082
+ {
1083
+ that._moveSplit( last_pos[ 0 ] - e.x );
1063
1084
  }
1064
- else {
1065
- that._moveSplit(last_pos[1] - e.y);
1085
+ else
1086
+ {
1087
+ that._moveSplit( last_pos[ 1 ] - e.y );
1066
1088
  }
1067
1089
 
1068
- last_pos[0] = e.x;
1069
- last_pos[1] = e.y;
1090
+ last_pos[ 0 ] = e.x;
1091
+ last_pos[ 1 ] = e.y;
1092
+
1093
+ const widgets = that.root.querySelectorAll( ".lexwidget" );
1094
+
1095
+ // Send area resize to every widget in the area
1096
+ for( let widget of widgets )
1097
+ {
1098
+ const jsInstance = widget.jsIinstance;
1099
+
1100
+ if( jsInstance.onresize )
1101
+ {
1102
+ jsInstance.onresize();
1103
+ }
1104
+ }
1105
+
1070
1106
  e.stopPropagation();
1071
1107
  e.preventDefault();
1072
1108
  }
1073
1109
 
1074
- function inner_mouseup(e)
1110
+ function inner_mouseup( e )
1075
1111
  {
1076
1112
  var doc = that.root.ownerDocument;
1077
- doc.removeEventListener("mousemove",inner_mousemove);
1078
- doc.removeEventListener("mouseup",inner_mouseup);
1079
- document.body.classList.remove("nocursor");
1080
- that.split_bar.classList.remove("nocursor");
1113
+ doc.removeEventListener( 'mousemove', inner_mousemove );
1114
+ doc.removeEventListener( 'mouseup', inner_mouseup );
1115
+ document.body.classList.remove( 'nocursor' );
1116
+ that.split_bar.classList.remove( 'nocursor' );
1081
1117
  }
1082
1118
 
1083
- // Is this necessary?..
1084
- // setTimeout( () => this._moveSplit(0), 100);
1085
-
1086
1119
  return this.sections;
1087
1120
  }
1088
1121
 
@@ -2596,7 +2629,8 @@ LX.ADD_CUSTOM_WIDGET = ADD_CUSTOM_WIDGET;
2596
2629
 
2597
2630
  class NodeTree {
2598
2631
 
2599
- constructor(domEl, data, options) {
2632
+ constructor( domEl, data, options ) {
2633
+
2600
2634
  this.domEl = domEl;
2601
2635
  this.data = data;
2602
2636
  this.onevent = options.onevent;
@@ -2604,10 +2638,10 @@ class NodeTree {
2604
2638
  this.selected = [];
2605
2639
 
2606
2640
  if(data.constructor === Object)
2607
- this._create_item(null, data);
2641
+ this._create_item( null, data );
2608
2642
  else
2609
2643
  for( let d of data )
2610
- this._create_item(null, d);
2644
+ this._create_item( null, d );
2611
2645
  }
2612
2646
 
2613
2647
  _create_item( parent, node, level = 0, selectedId ) {
@@ -2674,32 +2708,32 @@ class NodeTree {
2674
2708
  return;
2675
2709
  }
2676
2710
 
2677
- if(!e.shiftKey) {
2678
- list.querySelectorAll("li").forEach( e => { e.classList.remove('selected'); } );
2711
+ if( !e.shiftKey ) {
2712
+ list.querySelectorAll( "li" ).forEach( e => { e.classList.remove( 'selected' ); } );
2679
2713
  this.selected.length = 0;
2680
2714
  }
2681
2715
 
2682
2716
  // Add or remove
2683
2717
  const idx = this.selected.indexOf( node );
2684
2718
  if( idx > -1 ) {
2685
- item.classList.remove('selected');
2686
- this.selected.splice(idx, 1);
2719
+ item.classList.remove( 'selected' );
2720
+ this.selected.splice( idx, 1 );
2687
2721
  }else {
2688
- item.classList.add('selected');
2722
+ item.classList.add( 'selected' );
2689
2723
  this.selected.push( node );
2690
2724
  }
2691
2725
 
2692
2726
  // Only Show children...
2693
- if(is_parent && node.id.length > 1 /* Strange case... */) {
2727
+ if( is_parent && node.id.length > 1 /* Strange case... */) {
2694
2728
  node.closed = false;
2695
- if(that.onevent) {
2729
+ if( that.onevent ) {
2696
2730
  const event = new TreeEvent(TreeEvent.NODE_CARETCHANGED, node, node.closed);
2697
2731
  that.onevent( event );
2698
2732
  }
2699
2733
  that.frefresh( node.id );
2700
2734
  }
2701
2735
 
2702
- if(that.onevent) {
2736
+ if( that.onevent ) {
2703
2737
  const event = new TreeEvent(TreeEvent.NODE_SELECTED, e.shiftKey ? this.selected : node );
2704
2738
  event.multiple = e.shiftKey;
2705
2739
  that.onevent( event );
@@ -2707,15 +2741,17 @@ class NodeTree {
2707
2741
  });
2708
2742
 
2709
2743
  item.addEventListener("dblclick", function() {
2744
+
2710
2745
  if( that.options.rename ?? true )
2711
2746
  {
2712
2747
  // Trigger rename
2713
2748
  node.rename = true;
2714
2749
  that.refresh();
2715
2750
  }
2751
+
2716
2752
  if( that.onevent )
2717
2753
  {
2718
- const event = new TreeEvent(TreeEvent.NODE_DBLCLICKED, node);
2754
+ const event = new TreeEvent( TreeEvent.NODE_DBLCLICKED, node );
2719
2755
  that.onevent( event );
2720
2756
  }
2721
2757
  });
@@ -2725,19 +2761,88 @@ class NodeTree {
2725
2761
  if(that.onevent) {
2726
2762
  const event = new TreeEvent(TreeEvent.NODE_CONTEXTMENU, this.selected.length > 1 ? this.selected : node, e);
2727
2763
  event.multiple = this.selected.length > 1;
2764
+
2765
+ LX.addContextMenu( event.multiple ? "Selected Nodes" : event.node.id, event.value, m => {
2766
+ event.panel = m;
2767
+ });
2768
+
2728
2769
  that.onevent( event );
2770
+
2771
+ if( ( this.options.addDefault ?? false ) == true )
2772
+ {
2773
+ if( event.panel.items )
2774
+ {
2775
+ event.panel.add( "" );
2776
+ }
2777
+
2778
+ event.panel.add( "Select Children", () => {
2779
+
2780
+ const selectChildren = ( n ) => {
2781
+
2782
+ if( n.closed )
2783
+ {
2784
+ return;
2785
+ }
2786
+
2787
+ for( let child of n.children ?? [] )
2788
+ {
2789
+ if( !child )
2790
+ {
2791
+ continue;
2792
+ }
2793
+
2794
+ let nodeItem = this.domEl.querySelector( '#' + child.id );
2795
+ nodeItem.classList.add('selected');
2796
+ this.selected.push( child );
2797
+ selectChildren( child );
2798
+ }
2799
+ };
2800
+
2801
+ // Add childs of the clicked node
2802
+ selectChildren( node );
2803
+
2804
+ } );
2805
+
2806
+ // event.panel.add( "Clone", { callback: () => {
2807
+
2808
+ // } } );
2809
+
2810
+ event.panel.add( "Delete", { callback: () => {
2811
+
2812
+ // It's the root node
2813
+ if( !node.parent )
2814
+ {
2815
+ return;
2816
+ }
2817
+
2818
+ if( that.onevent ) {
2819
+ const event = new TreeEvent( TreeEvent.NODE_DELETED, node, e );
2820
+ that.onevent( event );
2821
+ }
2822
+
2823
+ // Delete nodes now
2824
+ let childs = node.parent.children;
2825
+ const index = childs.indexOf( node );
2826
+ childs.splice( index, 1 );
2827
+
2828
+ this.refresh();
2829
+ } } );
2830
+ }
2729
2831
  }
2730
2832
  });
2731
2833
 
2732
2834
  item.addEventListener("keydown", e => {
2733
- if(node.rename)
2734
- return;
2835
+
2836
+ if( node.rename )
2837
+ return;
2838
+
2735
2839
  e.preventDefault();
2840
+
2736
2841
  if( e.key == "Delete" )
2737
2842
  {
2738
2843
  // Send event now so we have the info in selected array..
2739
- if(that.onevent) {
2740
- const event = new TreeEvent(TreeEvent.NODE_DELETED, this.selected.length > 1 ? this.selected : node, e);
2844
+ if( that.onevent ) {
2845
+ const event = new TreeEvent( TreeEvent.NODE_DELETED, this.selected.length > 1 ? this.selected : node, e );
2741
2846
  event.multiple = this.selected.length > 1;
2742
2847
  that.onevent( event );
2743
2848
  }
@@ -2755,8 +2860,8 @@ class NodeTree {
2755
2860
  }
2756
2861
  else if( e.key == "ArrowUp" || e.key == "ArrowDown" ) // Unique or zero selected
2757
2862
  {
2758
- var selected = this.selected.length > 1 ? (e.key == "ArrowUp" ? this.selected.shift() : this.selected.pop()) : this.selected[0];
2759
- var el = this.domEl.querySelector("#" + LX.getSupportedDOMName( selected.id ) );
2863
+ var selected = this.selected.length > 1 ? ( e.key == "ArrowUp" ? this.selected.shift() : this.selected.pop() ) : this.selected[ 0 ];
2864
+ var el = this.domEl.querySelector( "#" + LX.getSupportedDOMName( selected.id ) );
2760
2865
  var sibling = e.key == "ArrowUp" ? el.previousSibling : el.nextSibling;
2761
2866
  if( sibling ) sibling.click();
2762
2867
  }
@@ -3227,7 +3332,7 @@ class Panel {
3227
3332
 
3228
3333
  if( type != Widget.TITLE )
3229
3334
  {
3230
- element.style.width = "calc(100% - " + (this.current_branch || type == Widget.FILE || ( type == Widget.BUTTON && !name ) ? 10 : 20) + "px)";
3335
+ element.style.width = "calc(100% - " + (this.current_branch || type == Widget.FILE ? 10 : 20) + "px)";
3231
3336
  if( options.width ) {
3232
3337
  element.style.width = element.style.minWidth = options.width;
3233
3338
  }
@@ -3279,6 +3384,7 @@ class Panel {
3279
3384
  }
3280
3385
 
3281
3386
  widget.domEl = element;
3387
+ element.jsIinstance = widget;
3282
3388
 
3283
3389
  const insert_widget = el => {
3284
3390
  if(options.container)
@@ -4046,37 +4152,39 @@ class Panel {
4046
4152
 
4047
4153
  addDropdown( name, values, value, callback, options = {} ) {
4048
4154
 
4049
- let widget = this.create_widget(name, Widget.DROPDOWN, options);
4155
+ let widget = this.create_widget( name, Widget.DROPDOWN, options );
4156
+
4050
4157
  widget.onGetValue = () => {
4051
- return element.querySelector("li.selected").getAttribute('value');
4158
+ return element.querySelector( "li.selected" ).getAttribute( 'value' );
4052
4159
  };
4160
+
4053
4161
  widget.onSetValue = ( newValue, skipCallback ) => {
4054
- let btn = element.querySelector(".lexwidgetname .lexicon");
4055
- if(btn) btn.style.display = (newValue != wValue.iValue ? "block" : "none");
4162
+ let btn = element.querySelector( ".lexwidgetname .lexicon" );
4163
+ if( btn ) btn.style.display = ( newValue != wValue.iValue ? "block" : "none" );
4056
4164
  value = newValue;
4057
- list.querySelectorAll('li').forEach( e => { if( e.getAttribute('value') == value ) e.click() } );
4058
- if( !skipCallback ) this._trigger( new IEvent(name, value, null), callback );
4165
+ list.querySelectorAll( 'li' ).forEach( e => { if( e.getAttribute('value') == value ) e.click() } );
4166
+ if( !skipCallback ) this._trigger( new IEvent( name, value, null ), callback );
4059
4167
  };
4060
4168
 
4061
4169
  let element = widget.domEl;
4062
4170
  let that = this;
4063
4171
 
4064
4172
  // Add reset functionality
4065
- if(widget.name && !(options.skipReset ?? false))
4173
+ if(widget.name && !( options.skipReset ?? false ))
4066
4174
  {
4067
- Panel._add_reset_property(element.domName, function() {
4175
+ Panel._add_reset_property( element.domName, function() {
4068
4176
  value = wValue.iValue;
4069
- list.querySelectorAll('li').forEach( e => { if( e.getAttribute('value') == value ) e.click() } );
4177
+ list.querySelectorAll( 'li' ).forEach( e => { if( e.getAttribute('value') == value ) e.click() } );
4070
4178
  this.style.display = "none";
4071
4179
  });
4072
4180
  }
4073
4181
 
4074
- let container = document.createElement('div');
4182
+ let container = document.createElement( 'div' );
4075
4183
  container.className = "lexdropdown";
4076
4184
  container.style.width = options.inputWidth || "calc( 100% - " + LX.DEFAULT_NAME_WIDTH + ")";
4077
4185
 
4078
4186
  // Add widget value
4079
- let wValue = document.createElement('div');
4187
+ let wValue = document.createElement( 'div' );
4080
4188
  wValue.className = "lexdropdown lexoption";
4081
4189
  wValue.name = name;
4082
4190
  wValue.iValue = value;
@@ -4087,14 +4195,15 @@ class Panel {
4087
4195
 
4088
4196
  this.queue(container);
4089
4197
 
4090
- let selectedOption = this.addButton(null, buttonName, (value, event) => {
4198
+ let selectedOption = this.addButton( null, buttonName, (value, event) => {
4091
4199
  if( list.unfocus_event ) {
4092
4200
  delete list.unfocus_event;
4093
4201
  return;
4094
4202
  }
4095
- element.querySelector(".lexoptions").style.top = (selectedOption.offsetTop + selectedOption.offsetHeight) + 'px';
4096
- element.querySelector(".lexoptions").style.width = (event.currentTarget.clientWidth) + 'px';
4097
- element.querySelector(".lexoptions").toggleAttribute('hidden');
4203
+ const topPosition = selectedOption.getBoundingClientRect().y;
4204
+ list.style.top = (topPosition + selectedOption.offsetHeight) + 'px';
4205
+ list.style.width = (event.currentTarget.clientWidth) + 'px';
4206
+ list.toggleAttribute('hidden');
4098
4207
  list.focus();
4099
4208
  }, { buttonClass: 'array', skipInlineCount: true });
4100
4209
 
@@ -4238,7 +4347,14 @@ class Panel {
4238
4347
  * @param {Function} callback Callback function on change
4239
4348
  * @param {*} options:
4240
4349
  * skipReset: Don't add the reset value button when value changes
4241
- */
4350
+ * bgColor: Widget background color
4351
+ * pointsColor: Curve points color
4352
+ * lineColor: Curve line color
4353
+ * noOverlap: Points do not overlap, replacing themselves if necessary
4354
+ * allowAddValues: Support adding values on click
4355
+ * smooth: Curve smoothness
4356
+ * moveOutAction: Clamp or delete points moved out of the curve (LX.CURVE_MOVEOUT_CLAMP, LX.CURVE_MOVEOUT_DELETE)
4357
+ */
4242
4358
 
4243
4359
  addCurve( name, values, callback, options = {} ) {
4244
4360
 
@@ -4248,34 +4364,36 @@ class Panel {
4248
4364
 
4249
4365
  let that = this;
4250
4366
  let widget = this.create_widget(name, Widget.CURVE, options);
4367
+
4251
4368
  widget.onGetValue = () => {
4252
- return JSON.parse(JSON.stringify(curve_instance.element.value));
4369
+ return JSON.parse(JSON.stringify(curveInstance.element.value));
4253
4370
  };
4371
+
4254
4372
  widget.onSetValue = ( newValue, skipCallback ) => {
4255
- let btn = element.querySelector(".lexwidgetname .lexicon");
4256
- if(btn) btn.style.display = (newValue != curve_instance.element.value ? "block" : "none");
4257
- curve_instance.element.value = JSON.parse(JSON.stringify(newValue));
4258
- curve_instance.redraw();
4259
- if( !skipCallback ) that._trigger( new IEvent(name, curve_instance.element.value, null), callback );
4373
+ let btn = element.querySelector( ".lexwidgetname .lexicon" );
4374
+ if( btn ) btn.style.display = ( newValue != curveInstance.element.value ? "block" : "none" );
4375
+ curveInstance.element.value = JSON.parse( JSON.stringify( newValue ) );
4376
+ curveInstance.redraw();
4377
+ if( !skipCallback ) that._trigger( new IEvent( name, curveInstance.element.value, null ), callback );
4260
4378
  };
4261
4379
 
4262
4380
  let element = widget.domEl;
4263
- let defaultValues = JSON.parse(JSON.stringify(values));
4381
+ let defaultValues = JSON.parse( JSON.stringify( values ) );
4264
4382
 
4265
4383
  // Add reset functionality
4266
4384
  if( !(options.skipReset ?? false) )
4267
4385
  {
4268
4386
  Panel._add_reset_property(element.domName, function(e) {
4269
4387
  this.style.display = "none";
4270
- curve_instance.element.value = JSON.parse(JSON.stringify(defaultValues));
4271
- curve_instance.redraw();
4272
- that._trigger( new IEvent(name, curve_instance.element.value, e), callback );
4388
+ curveInstance.element.value = JSON.parse( JSON.stringify( defaultValues ) );
4389
+ curveInstance.redraw();
4390
+ that._trigger( new IEvent( name, curveInstance.element.value, e ), callback );
4273
4391
  });
4274
4392
  }
4275
4393
 
4276
4394
  // Add widget value
4277
4395
 
4278
- var container = document.createElement('div');
4396
+ var container = document.createElement( 'div' );
4279
4397
  container.className = "lexcurve";
4280
4398
  container.style.width = "calc( 100% - " + LX.DEFAULT_NAME_WIDTH + ")";
4281
4399
 
@@ -4284,16 +4402,22 @@ class Panel {
4284
4402
  if(btn) btn.style.display = (v != defaultValues ? "block" : "none");
4285
4403
  that._trigger( new IEvent(name, v, e), callback );
4286
4404
  };
4405
+
4287
4406
  options.name = name;
4288
- let curve_instance = new Curve(this, values, options);
4289
- container.appendChild(curve_instance.element);
4290
- element.appendChild(container);
4407
+
4408
+ let curveInstance = new Curve( this, values, options );
4409
+ container.appendChild( curveInstance.element );
4410
+ element.appendChild( container );
4291
4411
 
4292
4412
  // Resize
4293
- curve_instance.canvas.width = container.offsetWidth;
4294
- curve_instance.redraw();
4295
- widget.onresize = curve_instance.redraw.bind(curve_instance);
4296
- widget.curve_instance = curve_instance;
4413
+ widget.onresize = curveInstance.redraw.bind( curveInstance );
4414
+ widget.curveInstance = curveInstance;
4415
+
4416
+ doAsync(() => {
4417
+ curveInstance.canvas.width = container.offsetWidth;
4418
+ curveInstance.redraw();
4419
+ });
4420
+
4297
4421
  return widget;
4298
4422
  }
4299
4423
 
@@ -4742,19 +4866,19 @@ class Panel {
4742
4866
  flag.id = "checkbox"+simple_guidGenerator();
4743
4867
  flag.innerHTML = "<a class='fa-solid fa-check' style='display: " + (flag.value ? "block" : "none") + "'></a>";
4744
4868
 
4745
- if(options.disabled) {
4869
+ if( options.disabled ) {
4746
4870
  flag.disabled = true;
4747
4871
  toggle.className += " disabled";
4748
4872
  }
4749
4873
 
4750
- toggle.appendChild(flag);
4874
+ toggle.appendChild( flag );
4751
4875
 
4752
- let value_name = document.createElement('span');
4876
+ let value_name = document.createElement( 'span' );
4753
4877
  value_name.id = "checkboxtext";
4754
4878
  value_name.innerHTML = "On";
4755
4879
 
4756
- container.appendChild(toggle);
4757
- container.appendChild(value_name);
4880
+ container.appendChild( toggle );
4881
+ container.appendChild( value_name );
4758
4882
 
4759
4883
  toggle.addEventListener( "click" , e => {
4760
4884
 
@@ -4762,7 +4886,7 @@ class Panel {
4762
4886
  if( flag.disabled )
4763
4887
  return;
4764
4888
 
4765
- const skipCallback = (e.detail.constructor == Number ? null : skipCallback);
4889
+ const skipCallback = ( e.detail.constructor == Number ? null : e.detail );
4766
4890
 
4767
4891
  let check = toggle.querySelector( ".checkbox a" );
4768
4892
 
@@ -4846,7 +4970,7 @@ class Panel {
4846
4970
  container.style.width = "calc( 100% - " + LX.DEFAULT_NAME_WIDTH + ")";
4847
4971
 
4848
4972
  let color = document.createElement( 'input' );
4849
- color.style.width = "calc(30% - 6px)";
4973
+ color.style.width = "32px";
4850
4974
  color.type = 'color';
4851
4975
  color.className = "colorinput";
4852
4976
  color.id = "color" + simple_guidGenerator();
@@ -4887,7 +5011,7 @@ class Panel {
4887
5011
  change_from_input = true;
4888
5012
  widget.set( v );
4889
5013
  change_from_input = false;
4890
- }, { width: "calc(70% - 4px)" });
5014
+ }, { width: "calc( 100% - 32px )"});
4891
5015
 
4892
5016
  text_widget.domEl.style.marginLeft = "4px";
4893
5017
 
@@ -6422,69 +6546,71 @@ LX.addContextMenu = addContextMenu;
6422
6546
 
6423
6547
  class Curve {
6424
6548
 
6425
- constructor(panel, value, options = {}) {
6549
+ constructor( panel, value, options = {} ) {
6426
6550
 
6427
- let element = document.createElement("div");
6428
- element.className = "curve " + (options.className ? options.className : "");
6551
+ let element = document.createElement( "div" );
6552
+ element.className = "curve " + ( options.className ? options.className : "" );
6429
6553
  element.style.minHeight = "50px";
6430
6554
  element.style.width = options.width || "100%";
6555
+ element.style.minWidth = "50px";
6556
+ element.style.minHeight = "20px";
6431
6557
 
6432
- element.bgcolor = options.bgcolor || LX.getThemeColor("global-dark-background");
6433
- element.pointscolor = options.pointscolor || LX.getThemeColor("global-selected-light");
6434
- element.linecolor = options.linecolor || "#555";
6435
-
6558
+ element.bgcolor = options.bgColor || LX.getThemeColor( "global-dark-background" );
6559
+ element.pointscolor = options.pointsColor || LX.getThemeColor( "global-selected-light" );
6560
+ element.linecolor = options.lineColor || "#555";
6436
6561
  element.value = value || [];
6437
- element.xrange = options.xrange || [0,1]; //min,max
6438
- element.yrange = options.yrange || [0,1]; //min,max
6562
+ element.xrange = options.xrange || [ 0, 1 ]; // min, max
6563
+ element.yrange = options.yrange || [ 0, 1 ]; // min, max
6439
6564
  element.defaulty = options.defaulty != null ? options.defaulty : 0.0;
6440
- element.no_trespassing = options.no_trespassing || false;
6441
- element.show_samples = options.show_samples || 0;
6442
- element.allow_add_values = options.allow_add_values ?? true;
6443
- element.draggable_x = options.draggable_x ?? true;
6444
- element.draggable_y = options.draggable_y ?? true;
6445
- element.smooth = (options.smooth && typeof(options.smooth) == 'number' ? options.smooth : 0.3) || false;
6446
- element.options = options;
6447
- element.style.minWidth = "50px";
6448
- element.style.minHeight = "20px";
6565
+ element.no_overlap = options.noOverlap || false;
6566
+ element.show_samples = options.showSamples || 0;
6567
+ element.allow_add_values = options.allowAddValues ?? true;
6568
+ element.draggable_x = options.draggableX ?? true;
6569
+ element.draggable_y = options.draggableY ?? true;
6570
+ element.smooth = (options.smooth && typeof( options.smooth ) == 'number' ? options.smooth : 0.3) || false;
6571
+ element.move_out = options.moveOutAction ?? LX.CURVE_MOVEOUT_DELETE;
6449
6572
 
6450
6573
  this.element = element;
6451
6574
 
6452
- let canvas = document.createElement("canvas");
6575
+ let canvas = document.createElement( "canvas" );
6453
6576
  canvas.width = options.width || 200;
6454
6577
  canvas.height = options.height || 50;
6455
6578
  element.appendChild( canvas );
6456
6579
  this.canvas = canvas;
6457
6580
 
6458
- element.addEventListener("mousedown", onmousedown);
6581
+ element.addEventListener( "mousedown", onmousedown );
6459
6582
 
6460
- element.getValueAt = function(x) {
6583
+ element.getValueAt = function( x ) {
6461
6584
 
6462
- if(x < element.xrange[0] || x > element.xrange[1])
6585
+ if( x < element.xrange[ 0 ] || x > element.xrange[ 1 ] )
6586
+ {
6463
6587
  return element.defaulty;
6588
+ }
6464
6589
 
6465
- var last = [ element.xrange[0], element.defaulty ];
6590
+ var last = [ element.xrange[ 0 ], element.defaulty ];
6466
6591
  var f = 0;
6467
- for(var i = 0; i < element.value.length; i += 1)
6592
+ for( var i = 0; i < element.value.length; i += 1 )
6468
6593
  {
6469
- var v = element.value[i];
6470
- if(x == v[0]) return v[1];
6471
- if(x < v[0])
6594
+ var v = element.value[ i ];
6595
+ if( x == v[ 0 ] ) return v[ 1 ];
6596
+ if( x < v[ 0 ] )
6472
6597
  {
6473
- f = (x - last[0]) / (v[0] - last[0]);
6474
- return last[1] * (1-f) + v[1] * f;
6598
+ f = ( x - last[ 0 ] ) / (v[ 0 ] - last[ 0 ]);
6599
+ return last[ 1 ] * ( 1 - f ) + v[ 1 ] * f;
6475
6600
  }
6601
+
6476
6602
  last = v;
6477
6603
  }
6478
6604
 
6479
- v = [ element.xrange[1], element.defaulty ];
6480
- f = (x - last[0]) / (v[0] - last[0]);
6481
- return last[1] * (1-f) + v[1] * f;
6605
+ v = [ element.xrange[ 1 ], element.defaulty ];
6606
+ f = (x - last[ 0 ]) / (v[ 0 ] - last[ 0 ]);
6607
+ return last[ 1 ] * ( 1 - f ) + v[ 1 ] * f;
6482
6608
  }
6483
6609
 
6484
- element.resample = function(samples) {
6610
+ element.resample = function( samples ) {
6485
6611
 
6486
6612
  var r = [];
6487
- var dx = (element.xrange[1] - element.xrange[0]) / samples;
6613
+ var dx = (element.xrange[1] - element.xrange[ 0 ]) / samples;
6488
6614
  for(var i = element.xrange[0]; i <= element.xrange[1]; i += dx)
6489
6615
  {
6490
6616
  r.push( element.getValueAt(i) );
@@ -6510,37 +6636,33 @@ class Curve {
6510
6636
  function convert(v) {
6511
6637
  return [ canvas.width * ( v[0] - element.xrange[0])/ (element.xrange[1]),
6512
6638
  canvas.height * (v[1] - element.yrange[0])/ (element.yrange[1])];
6513
- // return [ canvas.width * ( (element.xrange[1] - element.xrange[0]) * v[0] + element.xrange[0]),
6514
- // canvas.height * ((element.yrange[1] - element.yrange[0]) * v[1] + element.yrange[0])];
6515
6639
  }
6516
6640
 
6517
6641
  //canvas to value
6518
6642
  function unconvert(v) {
6519
6643
  return [(v[0] * element.xrange[1] / canvas.width + element.xrange[0]),
6520
6644
  (v[1] * element.yrange[1] / canvas.height + element.yrange[0])];
6521
- // return [(v[0] / canvas.width - element.xrange[0]) / (element.xrange[1] - element.xrange[0]),
6522
- // (v[1] / canvas.height - element.yrange[0]) / (element.yrange[1] - element.yrange[0])];
6523
6645
  }
6524
6646
 
6525
6647
  var selected = -1;
6526
6648
 
6527
- element.redraw = function(o = {} ) {
6649
+ element.redraw = function( o = {} ) {
6528
6650
 
6529
- if(o.value) element.value = o.value;
6530
- if(o.xrange) element.xrange = o.xrange;
6531
- if(o.yrange) element.yrange = o.yrange;
6532
- if(o.smooth) element.smooth = o.smooth;
6651
+ if( o.value ) element.value = o.value;
6652
+ if( o.xrange ) element.xrange = o.xrange;
6653
+ if( o.yrange ) element.yrange = o.yrange;
6654
+ if( o.smooth ) element.smooth = o.smooth;
6533
6655
  var rect = canvas.parentElement.getBoundingClientRect();
6534
- if(canvas.parentElement.parentElement) rect = canvas.parentElement.parentElement.getBoundingClientRect();
6535
- if(rect && canvas.width != rect.width && rect.width && rect.width < 1000)
6656
+ if( canvas.parentElement.parentElement ) rect = canvas.parentElement.parentElement.getBoundingClientRect();
6657
+ if( rect && canvas.width != rect.width && rect.width && rect.width < 1000 )
6658
+ {
6536
6659
  canvas.width = rect.width;
6537
- // if(rect && canvas.height != rect.height && rect.height && rect.height < 1000)
6538
- // canvas.height = rect.height;
6660
+ }
6539
6661
 
6540
- var ctx = canvas.getContext("2d");
6541
- ctx.setTransform(1, 0, 0, 1, 0, 0);
6542
- ctx.translate(0,canvas.height);
6543
- ctx.scale(1,-1);
6662
+ var ctx = canvas.getContext( "2d" );
6663
+ ctx.setTransform( 1, 0, 0, 1, 0, 0 );
6664
+ ctx.translate( 0, canvas.height );
6665
+ ctx.scale( 1, -1 );
6544
6666
 
6545
6667
  ctx.fillStyle = element.bgcolor;
6546
6668
  ctx.fillRect(0,0,canvas.width,canvas.height);
@@ -6549,40 +6671,42 @@ class Curve {
6549
6671
  ctx.beginPath();
6550
6672
 
6551
6673
  //draw line
6552
- var pos = convert([element.xrange[0],element.defaulty]);
6553
- ctx.moveTo( pos[0], pos[1] );
6554
- let values = [pos[0], pos[1]];
6674
+ var pos = convert([ element.xrange[ 0 ],element.defaulty ]);
6675
+ ctx.moveTo( pos[ 0 ], pos[ 1 ] );
6676
+ let values = [pos[ 0 ], pos[ 1 ]];
6555
6677
 
6556
6678
  for(var i in element.value) {
6557
6679
  var value = element.value[i];
6558
6680
  pos = convert(value);
6559
- values.push(pos[0]);
6560
- values.push(pos[1]);
6681
+ values.push(pos[ 0 ]);
6682
+ values.push(pos[ 1 ]);
6561
6683
  if(!element.smooth)
6562
- ctx.lineTo( pos[0], pos[1] );
6684
+ ctx.lineTo( pos[ 0 ], pos[ 1 ] );
6563
6685
  }
6564
6686
 
6565
- pos = convert([element.xrange[1],element.defaulty]);
6566
- values.push(pos[0]);
6567
- values.push(pos[1]);
6568
- if(!element.smooth) {
6569
- ctx.lineTo( pos[0], pos[1] );
6687
+ pos = convert([ element.xrange[ 1 ], element.defaulty ]);
6688
+ values.push(pos[ 0 ]);
6689
+ values.push(pos[ 1 ]);
6690
+ if( !element.smooth )
6691
+ {
6692
+ ctx.lineTo( pos[ 0 ], pos[ 1 ] );
6570
6693
  ctx.stroke();
6571
- } else {
6572
-
6573
- LX.UTILS.drawSpline(ctx, values, element.smooth);
6694
+ }
6695
+ else
6696
+ {
6697
+ LX.UTILS.drawSpline( ctx, values, element.smooth );
6574
6698
  }
6575
6699
 
6576
- //draw points
6577
- for(var i = 0; i < element.value.length; i += 1) {
6578
- var value = element.value[i];
6579
- pos = convert(value);
6580
- if(selected == i)
6700
+ // Draw points
6701
+ for( var i = 0; i < element.value.length; i += 1 ) {
6702
+ var value = element.value[ i ];
6703
+ pos = convert( value );
6704
+ if( selected == i )
6581
6705
  ctx.fillStyle = "white";
6582
6706
  else
6583
6707
  ctx.fillStyle = element.pointscolor;
6584
6708
  ctx.beginPath();
6585
- ctx.arc( pos[0], pos[1], selected == i ? 4 : 3, 0, Math.PI * 2);
6709
+ ctx.arc( pos[ 0 ], pos[ 1 ], selected == i ? 4 : 3, 0, Math.PI * 2);
6586
6710
  ctx.fill();
6587
6711
  }
6588
6712
 
@@ -6591,120 +6715,134 @@ class Curve {
6591
6715
  ctx.fillStyle = "#888";
6592
6716
  for(var i = 0; i < samples.length; i += 1)
6593
6717
  {
6594
- var value = [ i * ((element.xrange[1] - element.xrange[0]) / element.show_samples) + element.xrange[0], samples[i] ];
6718
+ var value = [ i * ((element.xrange[ 1 ] - element.xrange[ 0 ]) / element.show_samples) + element.xrange[ 0 ], samples[ i ] ];
6595
6719
  pos = convert(value);
6596
6720
  ctx.beginPath();
6597
- ctx.arc( pos[0], pos[1], 2, 0, Math.PI * 2);
6721
+ ctx.arc( pos[ 0 ], pos[ 1 ], 2, 0, Math.PI * 2);
6598
6722
  ctx.fill();
6599
6723
  }
6600
6724
  }
6601
6725
  }
6602
6726
 
6603
- var last_mouse = [0,0];
6727
+ var last_mouse = [ 0, 0 ];
6604
6728
 
6605
- function onmousedown(evt) {
6606
- document.addEventListener("mousemove",onmousemove);
6607
- document.addEventListener("mouseup",onmouseup);
6729
+ function onmousedown( e ) {
6730
+ document.addEventListener( "mousemove", onmousemove );
6731
+ document.addEventListener( "mouseup", onmouseup );
6608
6732
 
6609
6733
  var rect = canvas.getBoundingClientRect();
6610
- var mousex = evt.clientX - rect.left;
6611
- var mousey = evt.clientY - rect.top;
6734
+ var mousex = e.clientX - rect.left;
6735
+ var mousey = e.clientY - rect.top;
6612
6736
 
6613
- selected = computeSelected(mousex,canvas.height-mousey);
6737
+ selected = computeSelected( mousex, canvas.height - mousey );
6614
6738
 
6615
- if(selected == -1 && element.allow_add_values) {
6616
- var v = unconvert([mousex,canvas.height-mousey]);
6617
- element.value.push(v);
6739
+ if( e.button == LX.MOUSE_LEFT_CLICK && selected == -1 && element.allow_add_values ) {
6740
+ var v = unconvert([ mousex, canvas.height - mousey ]);
6741
+ element.value.push( v );
6618
6742
  sortValues();
6619
- selected = element.value.indexOf(v);
6743
+ selected = element.value.indexOf( v );
6620
6744
  }
6621
6745
 
6622
- last_mouse = [mousex,mousey];
6746
+ last_mouse = [ mousex, mousey ];
6623
6747
  element.redraw();
6624
- evt.preventDefault();
6625
- evt.stopPropagation();
6748
+ e.preventDefault();
6749
+ e.stopPropagation();
6626
6750
  }
6627
6751
 
6628
- function onmousemove(evt) {
6752
+ function onmousemove( e ) {
6753
+
6629
6754
  var rect = canvas.getBoundingClientRect();
6630
- var mousex = evt.clientX - rect.left;
6631
- var mousey = evt.clientY - rect.top;
6755
+ var mousex = e.clientX - rect.left;
6756
+ var mousey = e.clientY - rect.top;
6632
6757
 
6633
- if(mousex < 0) mousex = 0;
6634
- else if(mousex > canvas.width) mousex = canvas.width;
6635
- if(mousey < 0) mousey = 0;
6636
- else if(mousey > canvas.height) mousey = canvas.height;
6758
+ if( mousex < 0 ) mousex = 0;
6759
+ else if( mousex > canvas.width ) mousex = canvas.width;
6760
+ if( mousey < 0 ) mousey = 0;
6761
+ else if( mousey > canvas.height ) mousey = canvas.height;
6637
6762
 
6638
- //dragging to remove
6639
- if( selected != -1 && distance( [evt.clientX - rect.left, evt.clientY - rect.top], [mousex,mousey] ) > canvas.height * 0.5 )
6763
+ // Dragging to remove
6764
+ const currentMouseDiff = [ e.clientX - rect.left, e.clientY - rect.top ];
6765
+ if( selected != -1 && distance( currentMouseDiff, [ mousex, mousey ] ) > canvas.height * 0.5 )
6640
6766
  {
6641
- element.value.splice(selected,1);
6642
- onmouseup(evt);
6767
+ if( element.move_out == LX.CURVE_MOVEOUT_DELETE)
6768
+ {
6769
+ element.value.splice( selected, 1 );
6770
+ }
6771
+ else
6772
+ {
6773
+ const d = [ currentMouseDiff[ 0 ] - mousex, currentMouseDiff[ 1 ] - mousey ];
6774
+ let value = element.value[ selected ];
6775
+ value[ 0 ] = ( d[ 0 ] == 0.0 ) ? value[ 0 ] : ( d[ 0 ] < 0.0 ? element.xrange[ 0 ] : element.xrange[ 1 ] );
6776
+ value[ 1 ] = ( d[ 1 ] == 0.0 ) ? value[ 1 ] : ( d[ 1 ] < 0.0 ? element.yrange[ 1 ] : element.yrange[ 0 ] );
6777
+ }
6778
+
6779
+ onmouseup( e );
6643
6780
  return;
6644
6781
  }
6645
6782
 
6646
- var dx = element.draggable_x ? last_mouse[0] - mousex : 0;
6647
- var dy = element.draggable_y ? last_mouse[1] - mousey : 0;
6648
- var delta = unconvert([-dx,dy]);
6649
- if(selected != -1) {
6650
- var minx = element.xrange[0];
6651
- var maxx = element.xrange[1];
6783
+ var dx = element.draggable_x ? last_mouse[ 0 ] - mousex : 0;
6784
+ var dy = element.draggable_y ? last_mouse[ 1 ] - mousey : 0;
6785
+ var delta = unconvert([ -dx, dy ]);
6652
6786
 
6653
- if(element.no_trespassing)
6787
+ if( selected != -1 ) {
6788
+ var minx = element.xrange[ 0 ];
6789
+ var maxx = element.xrange[ 1 ];
6790
+
6791
+ if( element.no_overlap )
6654
6792
  {
6655
- if(selected > 0) minx = element.value[selected-1][0];
6656
- if(selected < (element.value.length-1) ) maxx = element.value[selected+1][0];
6793
+ if( selected > 0) minx = element.value[ selected - 1 ][ 0 ];
6794
+ if( selected < ( element.value.length - 1 ) ) maxx = element.value[ selected + 1 ][ 0 ];
6657
6795
  }
6658
6796
 
6659
6797
  var v = element.value[selected];
6660
- v[0] += delta[0];
6661
- v[1] += delta[1];
6662
- if(v[0] < minx) v[0] = minx;
6663
- else if(v[0] > maxx) v[0] = maxx;
6664
- if(v[1] < element.yrange[0]) v[1] = element.yrange[0];
6665
- else if(v[1] > element.yrange[1]) v[1] = element.yrange[1];
6798
+ v[ 0 ] += delta[ 0 ];
6799
+ v[ 1 ] += delta[ 1 ];
6800
+ if(v[ 0 ] < minx) v[ 0 ] = minx;
6801
+ else if(v[ 0 ] > maxx) v[ 0 ] = maxx;
6802
+ if(v[ 1 ] < element.yrange[ 0 ]) v[ 1 ] = element.yrange[ 0 ];
6803
+ else if(v[ 1 ] > element.yrange[ 1 ]) v[ 1 ] = element.yrange[ 1 ];
6666
6804
  }
6667
6805
 
6668
6806
  sortValues();
6669
6807
  element.redraw();
6670
- last_mouse[0] = mousex;
6671
- last_mouse[1] = mousey;
6672
- onchange(evt);
6808
+ last_mouse[ 0 ] = mousex;
6809
+ last_mouse[ 1 ] = mousey;
6810
+ onchange( e );
6673
6811
 
6674
- evt.preventDefault();
6675
- evt.stopPropagation();
6812
+ e.preventDefault();
6813
+ e.stopPropagation();
6676
6814
  }
6677
6815
 
6678
- function onmouseup(evt) {
6816
+ function onmouseup( e ) {
6679
6817
  selected = -1;
6680
6818
  element.redraw();
6681
6819
  document.removeEventListener("mousemove", onmousemove);
6682
6820
  document.removeEventListener("mouseup", onmouseup);
6683
- onchange(evt);
6684
- evt.preventDefault();
6685
- evt.stopPropagation();
6821
+ onchange(e);
6822
+ e.preventDefault();
6823
+ e.stopPropagation();
6686
6824
  }
6687
6825
 
6688
- function onchange(e) {
6689
- if(options.callback)
6690
- options.callback.call(element, element.value, e);
6826
+ function onchange( e ) {
6827
+ if( options.callback )
6828
+ options.callback.call( element, element.value, e );
6691
6829
  }
6692
6830
 
6693
6831
  function distance(a,b) { return Math.sqrt( Math.pow(b[0]-a[0],2) + Math.pow(b[1]-a[1],2) ); };
6694
6832
 
6695
- function computeSelected(x,y) {
6833
+ function computeSelected( x, y ) {
6696
6834
 
6697
- var min_dist = 100000;
6698
- var max_dist = 8; //pixels
6835
+ var minDistance = 100000;
6836
+ var maxDistance = 8; //pixels
6699
6837
  var selected = -1;
6700
- for(var i=0; i < element.value.length; i++)
6838
+ for( var i = 0; i < element.value.length; i++ )
6701
6839
  {
6702
- var value = element.value[i];
6703
- var pos = convert(value);
6704
- var dist = distance([x,y],pos);
6705
- if(dist < min_dist && dist < max_dist)
6840
+ var value = element.value[ i ];
6841
+ var pos = convert( value );
6842
+ var dist = distance( [ x,y ], pos );
6843
+ if( dist < minDistance && dist < maxDistance )
6706
6844
  {
6707
- min_dist = dist;
6845
+ minDistance = dist;
6708
6846
  selected = i;
6709
6847
  }
6710
6848
  }
@@ -6713,19 +6851,24 @@ class Curve {
6713
6851
 
6714
6852
  function sortValues() {
6715
6853
  var v = null;
6716
- if(selected != -1)
6717
- v = element.value[selected];
6718
- element.value.sort(function(a,b) { return a[0] - b[0]; });
6719
- if(v)
6720
- selected = element.value.indexOf(v);
6854
+ if( selected != -1 )
6855
+ {
6856
+ v = element.value[ selected ];
6857
+ }
6858
+ element.value.sort(function( a,b ) { return a[ 0 ] - b[ 0 ]; });
6859
+ if( v )
6860
+ {
6861
+ selected = element.value.indexOf( v );
6862
+ }
6721
6863
  }
6722
6864
 
6723
6865
  element.redraw();
6724
6866
  return this;
6725
6867
  }
6726
6868
 
6727
- redraw(options = {}) {
6728
- this.element.redraw(options);
6869
+ redraw( options = {} ) {
6870
+ console.log("REDRAW!!");
6871
+ this.element.redraw( options );
6729
6872
  }
6730
6873
  }
6731
6874