lexgui 0.6.11 → 0.7.0
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 +14 -9
- package/build/{components → extensions}/audio.js +11 -11
- package/build/{components → extensions}/codeeditor.js +109 -74
- package/build/{components → extensions}/docmaker.js +10 -3
- package/build/{components → extensions}/imui.js +19 -12
- package/build/{components → extensions}/nodegraph.js +1 -1
- package/build/{components → extensions}/timeline.js +150 -94
- package/build/{components → extensions}/videoeditor.js +1 -1
- package/build/lexgui-docs.css +9 -9
- package/build/lexgui.css +489 -223
- package/build/lexgui.js +1771 -777
- package/build/lexgui.min.css +2 -2
- package/build/lexgui.min.js +1 -1
- package/build/lexgui.module.js +1803 -809
- package/build/lexgui.module.min.js +1 -1
- package/changelog.md +90 -21
- package/demo.js +52 -32
- package/examples/{all_widgets.html → all-components.html} +22 -4
- package/examples/{area_tabs.html → area-tabs.html} +3 -3
- package/examples/{asset_view.html → asset-view.html} +3 -3
- package/examples/{code_editor.html → code-editor.html} +4 -4
- package/examples/dialogs.html +3 -3
- package/examples/editor.html +27 -18
- package/examples/{immediate_ui.html → immediate-ui.html} +3 -3
- package/examples/index.html +8 -8
- package/examples/{node_graph.html → node-graph.html} +3 -3
- package/examples/previews/all-components.png +0 -0
- package/examples/previews/area-tabs.png +0 -0
- package/examples/previews/asset-view.png +0 -0
- package/examples/previews/code-editor.png +0 -0
- package/examples/previews/dialogs.png +0 -0
- package/examples/previews/editor.png +0 -0
- package/examples/previews/node-graph.png +0 -0
- package/examples/previews/side-bar.png +0 -0
- package/examples/previews/timeline.png +0 -0
- package/examples/{side_bar.html → side-bar.html} +3 -3
- package/examples/timeline.html +5 -5
- package/examples/{video_editor.html → video-editor.html} +3 -3
- package/examples/{video_editor2.html → video-editor2.html} +3 -3
- package/package.json +2 -2
- package/examples/previews/all_widgets.png +0 -0
- package/examples/previews/area_tabs.png +0 -0
- package/examples/previews/asset_view.png +0 -0
- package/examples/previews/code_editor.png +0 -0
- package/examples/previews/node_graph.png +0 -0
- package/examples/previews/side_bar.png +0 -0
package/README.md
CHANGED
|
@@ -1,6 +1,9 @@
|
|
|
1
|
+

|
|
2
|
+

|
|
3
|
+
|
|
1
4
|
# lexgui.js
|
|
2
5
|
|
|
3
|
-
**lexgui.js** is a lightweight JavaScript library for building web interfaces. No bloated frameworks, no unnecessary complexity, just pure HTML, CSS, and JavaScript magic. It gives you an easy API for crafting dynamic, interactive editor interfaces without the headache of big libraries.
|
|
6
|
+
**lexgui.js** is a lightweight JavaScript library for building web user interfaces. No bloated frameworks, no unnecessary complexity, just pure HTML, CSS, and JavaScript magic. It gives you an easy API for crafting dynamic, interactive editor interfaces without the headache of big libraries.
|
|
4
7
|
|
|
5
8
|
NPM Package: [npmjs.com/package/lexgui](https://www.npmjs.com/package/lexgui)
|
|
6
9
|
|
|
@@ -18,12 +21,14 @@ NPM Package: [npmjs.com/package/lexgui](https://www.npmjs.com/package/lexgui)
|
|
|
18
21
|
</tr>
|
|
19
22
|
</table>
|
|
20
23
|
|
|
21
|
-
##
|
|
24
|
+
## Extension Features
|
|
22
25
|
|
|
23
|
-
- [x] Asset Browser
|
|
24
26
|
- [x] Timeline
|
|
25
27
|
- [x] Code Editor
|
|
26
|
-
- [
|
|
28
|
+
- [x] Docs Maker
|
|
29
|
+
- [ ] Node Graph Editor (WIP)
|
|
30
|
+
- [ ] Video Editor (WIP)
|
|
31
|
+
- [ ] Immediate UI (WIP)
|
|
27
32
|
|
|
28
33
|
## Quick start
|
|
29
34
|
|
|
@@ -40,7 +45,7 @@ NPM Package: [npmjs.com/package/lexgui](https://www.npmjs.com/package/lexgui)
|
|
|
40
45
|
{
|
|
41
46
|
"imports": {
|
|
42
47
|
"lexgui": "https://cdn.skypack.dev/lexgui@^<version>/build/lexgui.module.js",
|
|
43
|
-
"lexgui/
|
|
48
|
+
"lexgui/extensions/": "https://cdn.skypack.dev/lexgui@^<version>/build/extensions/"
|
|
44
49
|
}
|
|
45
50
|
}
|
|
46
51
|
</script>
|
|
@@ -56,8 +61,8 @@ NPM Package: [npmjs.com/package/lexgui](https://www.npmjs.com/package/lexgui)
|
|
|
56
61
|
```js
|
|
57
62
|
import { LX } from 'lexgui';
|
|
58
63
|
|
|
59
|
-
// Using
|
|
60
|
-
import { CodeEditor } from 'lexgui/
|
|
64
|
+
// Using extensions
|
|
65
|
+
import { CodeEditor } from 'lexgui/extensions/codeeditor.js';
|
|
61
66
|
|
|
62
67
|
// Create main area
|
|
63
68
|
let area = await LX.init();
|
|
@@ -68,7 +73,7 @@ let panel = area.addPanel();
|
|
|
68
73
|
// Start branch/section
|
|
69
74
|
panel.branch("Section Title");
|
|
70
75
|
|
|
71
|
-
// Add some
|
|
76
|
+
// Add some components
|
|
72
77
|
panel.addButton(null, "Click me, Im Full Width...");
|
|
73
78
|
panel.addText("Text", "Warning text", null, { warning: true });
|
|
74
79
|
|
|
@@ -82,7 +87,7 @@ The library documentation is available at [lexgui.js/docs/](https://jxarco.githu
|
|
|
82
87
|
|
|
83
88
|
## Examples
|
|
84
89
|
|
|
85
|
-
Look at this [examples](https://jxarco.github.io/lexgui.js/examples/) to see how to create the different
|
|
90
|
+
Look at this [examples](https://jxarco.github.io/lexgui.js/examples/) to see how to create the different components and integrate the extensions!
|
|
86
91
|
|
|
87
92
|
## Projects using lexgui.js
|
|
88
93
|
|
|
@@ -5,14 +5,14 @@ if( !LX )
|
|
|
5
5
|
throw("lexgui.js missing!");
|
|
6
6
|
}
|
|
7
7
|
|
|
8
|
-
LX.
|
|
8
|
+
LX.extensions.push( 'Audio' );
|
|
9
9
|
|
|
10
10
|
/**
|
|
11
11
|
* @class Knob
|
|
12
|
-
* @description Knob
|
|
12
|
+
* @description Knob Component
|
|
13
13
|
*/
|
|
14
14
|
|
|
15
|
-
class Knob extends LX.
|
|
15
|
+
class Knob extends LX.BaseComponent {
|
|
16
16
|
|
|
17
17
|
constructor( name, value, min, max, callback, options = {} ) {
|
|
18
18
|
|
|
@@ -22,7 +22,7 @@ class Knob extends LX.Widget {
|
|
|
22
22
|
value = options.precision ? LX.round( value, options.precision ) : value;
|
|
23
23
|
}
|
|
24
24
|
|
|
25
|
-
super( LX.
|
|
25
|
+
super( LX.BaseComponent.KNOB, name, value, options );
|
|
26
26
|
|
|
27
27
|
this.onGetValue = () => {
|
|
28
28
|
return innerKnobCircle.value;
|
|
@@ -30,7 +30,7 @@ class Knob extends LX.Widget {
|
|
|
30
30
|
|
|
31
31
|
this.onSetValue = ( newValue, skipCallback ) => {
|
|
32
32
|
innerSetValue( newValue );
|
|
33
|
-
LX.
|
|
33
|
+
LX.BaseComponent._dispatchEvent( innerKnobCircle, "change", skipCallback );
|
|
34
34
|
};
|
|
35
35
|
|
|
36
36
|
this.onResize = ( rect ) => {
|
|
@@ -107,7 +107,7 @@ class Knob extends LX.Widget {
|
|
|
107
107
|
// Reset button (default value)
|
|
108
108
|
if( !skipCallback )
|
|
109
109
|
{
|
|
110
|
-
let btn = this.root.querySelector( ".
|
|
110
|
+
let btn = this.root.querySelector( ".lexcomponentname .lexicon" );
|
|
111
111
|
if( btn ) btn.style.display = val != innerKnobCircle.iValue ? "block": "none";
|
|
112
112
|
|
|
113
113
|
if( !( snapEnabled && !mustSnap ) )
|
|
@@ -157,7 +157,7 @@ class Knob extends LX.Widget {
|
|
|
157
157
|
else if(e.altKey) mult *= 0.1;
|
|
158
158
|
let new_value = (innerKnobCircle.value - mult * dt);
|
|
159
159
|
innerKnobCircle.value = new_value;
|
|
160
|
-
LX.
|
|
160
|
+
LX.BaseComponent._dispatchEvent( innerKnobCircle, 'change' );
|
|
161
161
|
}
|
|
162
162
|
|
|
163
163
|
e.stopPropagation();
|
|
@@ -175,7 +175,7 @@ class Knob extends LX.Widget {
|
|
|
175
175
|
if( snapEnabled )
|
|
176
176
|
{
|
|
177
177
|
mustSnap = true;
|
|
178
|
-
LX.
|
|
178
|
+
LX.BaseComponent._dispatchEvent( innerKnobCircle, 'change' );
|
|
179
179
|
}
|
|
180
180
|
|
|
181
181
|
if( document.pointerLockElement )
|
|
@@ -196,7 +196,7 @@ LX.Knob = Knob;
|
|
|
196
196
|
|
|
197
197
|
/**
|
|
198
198
|
* @method addKnob
|
|
199
|
-
* @param {String} name
|
|
199
|
+
* @param {String} name Component name
|
|
200
200
|
* @param {Number} value Knob value
|
|
201
201
|
* @param {Number} min Min Knob value
|
|
202
202
|
* @param {Number} max Max Knob value
|
|
@@ -207,6 +207,6 @@ LX.Knob = Knob;
|
|
|
207
207
|
*/
|
|
208
208
|
|
|
209
209
|
LX.Panel.prototype.addKnob = function( name, value, min, max, callback, options = {} ) {
|
|
210
|
-
const
|
|
211
|
-
return this.
|
|
210
|
+
const component = new Knob( name, value, min, max, callback, options );
|
|
211
|
+
return this._attachComponent( component );
|
|
212
212
|
}
|
|
@@ -4,7 +4,7 @@ if(!LX) {
|
|
|
4
4
|
throw("lexgui.js missing!");
|
|
5
5
|
}
|
|
6
6
|
|
|
7
|
-
LX.
|
|
7
|
+
LX.extensions.push( 'CodeEditor' );
|
|
8
8
|
|
|
9
9
|
function swapElements( obj, a, b ) {
|
|
10
10
|
[obj[a], obj[b]] = [obj[b], obj[a]];
|
|
@@ -458,7 +458,7 @@ class CodeEditor {
|
|
|
458
458
|
const dX = ( e.deltaY > 0.0 ? 10.0 : -10.0 ) * ( e.shiftKey ? 1.0 : 0.0 );
|
|
459
459
|
if( dX != 0.0 ) this.setScrollBarValue( 'horizontal', dX );
|
|
460
460
|
}
|
|
461
|
-
});
|
|
461
|
+
}, { passive: true });
|
|
462
462
|
}
|
|
463
463
|
}
|
|
464
464
|
|
|
@@ -822,8 +822,9 @@ class CodeEditor {
|
|
|
822
822
|
this.resetCursorPos( CodeEditor.CURSOR_LEFT, cursor );
|
|
823
823
|
this.cursorToString( cursor, this.code.lines[ ln ] );
|
|
824
824
|
|
|
825
|
-
|
|
826
|
-
|
|
825
|
+
var viewportSizeX = ( this.codeScroller.clientWidth + this.getScrollLeft() ) - CodeEditor.LINE_GUTTER_WIDTH; // Gutter offset
|
|
826
|
+
if( ( cursor.position * this.charWidth ) >= viewportSizeX )
|
|
827
|
+
this.setScrollLeft( this.code.lines[ ln ].length * this.charWidth );
|
|
827
828
|
|
|
828
829
|
// Merge cursors
|
|
829
830
|
this.mergeCursors( ln );
|
|
@@ -1097,39 +1098,50 @@ class CodeEditor {
|
|
|
1097
1098
|
this.loadedTabs = { };
|
|
1098
1099
|
this.openedTabs = { };
|
|
1099
1100
|
|
|
1101
|
+
const onLoadAll = () => {
|
|
1102
|
+
// Create inspector panel when the initial state is complete
|
|
1103
|
+
// and we have at least 1 tab opened
|
|
1104
|
+
this.infoPanel = this._createInfoPanel();
|
|
1105
|
+
if( this.infoPanel )
|
|
1106
|
+
{
|
|
1107
|
+
area.attach( this.infoPanel );
|
|
1108
|
+
}
|
|
1109
|
+
|
|
1110
|
+
// Wait until the fonts are all loaded
|
|
1111
|
+
document.fonts.ready.then(() => {
|
|
1112
|
+
this.charWidth = this._measureChar( "a", true );
|
|
1113
|
+
});
|
|
1114
|
+
|
|
1115
|
+
window.editor = this;
|
|
1116
|
+
};
|
|
1117
|
+
|
|
1100
1118
|
if( options.allowAddScripts ?? true )
|
|
1101
1119
|
{
|
|
1102
1120
|
this.addTab("+", false, "New File");
|
|
1103
1121
|
}
|
|
1104
1122
|
|
|
1105
|
-
|
|
1106
|
-
|
|
1107
|
-
|
|
1108
|
-
|
|
1109
|
-
|
|
1123
|
+
if( options.files )
|
|
1124
|
+
{
|
|
1125
|
+
console.assert( options.files.constructor === Array, "_files_ must be an Array!" );
|
|
1126
|
+
const numFiles = options.files.length;
|
|
1127
|
+
let filesLoaded = 0;
|
|
1110
1128
|
|
|
1111
|
-
|
|
1112
|
-
const commitMono = new FontFace(
|
|
1113
|
-
"CommitMono",
|
|
1114
|
-
`url(${ fontUrl })`,
|
|
1129
|
+
for( let url of options.files )
|
|
1115
1130
|
{
|
|
1116
|
-
|
|
1117
|
-
|
|
1118
|
-
|
|
1131
|
+
this.loadFile( url, { callback: () => {
|
|
1132
|
+
filesLoaded++;
|
|
1133
|
+
if( filesLoaded == numFiles )
|
|
1134
|
+
{
|
|
1135
|
+
onLoadAll();
|
|
1136
|
+
}
|
|
1137
|
+
}});
|
|
1119
1138
|
}
|
|
1120
|
-
|
|
1121
|
-
|
|
1122
|
-
|
|
1123
|
-
|
|
1124
|
-
|
|
1125
|
-
|
|
1126
|
-
commitMono.load();
|
|
1127
|
-
|
|
1128
|
-
// Wait until the fonts are all loaded
|
|
1129
|
-
document.fonts.ready.then(() => {
|
|
1130
|
-
// console.log("commitMono loaded")
|
|
1131
|
-
this.charWidth = this._measureChar( "a", true );
|
|
1132
|
-
});
|
|
1139
|
+
}
|
|
1140
|
+
else
|
|
1141
|
+
{
|
|
1142
|
+
this.addTab( options.name || "untitled", true, options.title, { language: options.highlight ?? "Plain Text" } );
|
|
1143
|
+
onLoadAll();
|
|
1144
|
+
}
|
|
1133
1145
|
}
|
|
1134
1146
|
|
|
1135
1147
|
static getInstances()
|
|
@@ -1287,6 +1299,11 @@ class CodeEditor {
|
|
|
1287
1299
|
this._changeLanguageFromExtension( LX.getExtension( name ) );
|
|
1288
1300
|
}
|
|
1289
1301
|
}
|
|
1302
|
+
|
|
1303
|
+
if( options.callback )
|
|
1304
|
+
{
|
|
1305
|
+
options.callback( text );
|
|
1306
|
+
}
|
|
1290
1307
|
};
|
|
1291
1308
|
|
|
1292
1309
|
if( file.constructor == String )
|
|
@@ -1560,7 +1577,7 @@ class CodeEditor {
|
|
|
1560
1577
|
this._changeLanguage( 'Plain Text' );
|
|
1561
1578
|
}
|
|
1562
1579
|
|
|
1563
|
-
|
|
1580
|
+
_createInfoPanel() {
|
|
1564
1581
|
|
|
1565
1582
|
if( !this.skipInfo )
|
|
1566
1583
|
{
|
|
@@ -2859,18 +2876,18 @@ class CodeEditor {
|
|
|
2859
2876
|
}
|
|
2860
2877
|
|
|
2861
2878
|
const lang = this.languages[ this.highlight ];
|
|
2862
|
-
const
|
|
2863
|
-
const
|
|
2879
|
+
const localLineNum = this.toLocalLine( linenum );
|
|
2880
|
+
const gutterLineHtml = "<span class='line-gutter'>" + (linenum + 1) + "</span>";
|
|
2864
2881
|
|
|
2865
2882
|
const UPDATE_LINE = ( html ) => {
|
|
2866
2883
|
if( !force ) // Single line update
|
|
2867
2884
|
{
|
|
2868
|
-
this.code.childNodes[
|
|
2885
|
+
this.code.childNodes[ localLineNum ].innerHTML = gutterLineHtml + html;
|
|
2869
2886
|
this._setActiveLine( linenum );
|
|
2870
2887
|
this._clearTmpVariables();
|
|
2871
2888
|
}
|
|
2872
2889
|
else // Update all lines at once
|
|
2873
|
-
return "<pre>" + (
|
|
2890
|
+
return "<pre>" + ( gutterLineHtml + html ) + "</pre>";
|
|
2874
2891
|
}
|
|
2875
2892
|
|
|
2876
2893
|
// multi-line strings not supported by now
|
|
@@ -2883,14 +2900,15 @@ class CodeEditor {
|
|
|
2883
2900
|
// Single line
|
|
2884
2901
|
if( !force )
|
|
2885
2902
|
{
|
|
2886
|
-
LX.deleteElement( this.code.childNodes[
|
|
2887
|
-
this.code.insertChildAtIndex( document.createElement( 'pre' ),
|
|
2903
|
+
LX.deleteElement( this.code.childNodes[ localLineNum ] );
|
|
2904
|
+
this.code.insertChildAtIndex( document.createElement( 'pre' ), localLineNum );
|
|
2888
2905
|
}
|
|
2889
2906
|
|
|
2890
2907
|
// Early out check for no highlighting languages
|
|
2891
2908
|
if( this.highlight == 'Plain Text' )
|
|
2892
2909
|
{
|
|
2893
|
-
|
|
2910
|
+
const plainTextHtml = linestring.replaceAll('<', '<').replaceAll('>', '>');
|
|
2911
|
+
return UPDATE_LINE( plainTextHtml );
|
|
2894
2912
|
}
|
|
2895
2913
|
|
|
2896
2914
|
this._currentLineNumber = linenum;
|
|
@@ -2899,9 +2917,11 @@ class CodeEditor {
|
|
|
2899
2917
|
const tokensToEvaluate = this._getTokensFromLine( linestring );
|
|
2900
2918
|
|
|
2901
2919
|
if( !tokensToEvaluate.length )
|
|
2902
|
-
|
|
2920
|
+
{
|
|
2921
|
+
return "<pre><span class='line-gutter'>" + linenum + "</span></pre>";
|
|
2922
|
+
}
|
|
2903
2923
|
|
|
2904
|
-
var
|
|
2924
|
+
var lineInnerHtml = "";
|
|
2905
2925
|
|
|
2906
2926
|
// Process all tokens
|
|
2907
2927
|
for( var i = 0; i < tokensToEvaluate.length; ++i )
|
|
@@ -2929,7 +2949,7 @@ class CodeEditor {
|
|
|
2929
2949
|
this._buildingBlockComment = linenum;
|
|
2930
2950
|
}
|
|
2931
2951
|
|
|
2932
|
-
|
|
2952
|
+
lineInnerHtml += this._evaluateToken( {
|
|
2933
2953
|
token: token,
|
|
2934
2954
|
prev: prev,
|
|
2935
2955
|
prevWithSpaces: tokensToEvaluate[ i - 1 ],
|
|
@@ -2942,7 +2962,7 @@ class CodeEditor {
|
|
|
2942
2962
|
} );
|
|
2943
2963
|
}
|
|
2944
2964
|
|
|
2945
|
-
return UPDATE_LINE(
|
|
2965
|
+
return UPDATE_LINE( lineInnerHtml );
|
|
2946
2966
|
}
|
|
2947
2967
|
|
|
2948
2968
|
_lineHasComment( linestring ) {
|
|
@@ -3564,12 +3584,12 @@ class CodeEditor {
|
|
|
3564
3584
|
this.restartBlink();
|
|
3565
3585
|
|
|
3566
3586
|
// Add horizontal scroll
|
|
3567
|
-
|
|
3568
|
-
|
|
3569
|
-
|
|
3570
|
-
|
|
3571
|
-
|
|
3572
|
-
}
|
|
3587
|
+
const currentScrollLeft = this.getScrollLeft();
|
|
3588
|
+
var viewportSizeX = ( this.codeScroller.clientWidth + currentScrollLeft ) - CodeEditor.LINE_GUTTER_WIDTH; // Gutter offset
|
|
3589
|
+
if( (cursor.position * this.charWidth) >= viewportSizeX )
|
|
3590
|
+
{
|
|
3591
|
+
this.setScrollLeft( currentScrollLeft + this.charWidth );
|
|
3592
|
+
}
|
|
3573
3593
|
}
|
|
3574
3594
|
|
|
3575
3595
|
cursorToLeft( key, cursor ) {
|
|
@@ -3585,11 +3605,12 @@ class CodeEditor {
|
|
|
3585
3605
|
|
|
3586
3606
|
// Add horizontal scroll
|
|
3587
3607
|
|
|
3588
|
-
|
|
3589
|
-
|
|
3590
|
-
|
|
3591
|
-
|
|
3592
|
-
|
|
3608
|
+
const currentScrollLeft = this.getScrollLeft();
|
|
3609
|
+
var viewportSizeX = currentScrollLeft; // Gutter offset
|
|
3610
|
+
if( ( ( cursor.position - 1 ) * this.charWidth ) < viewportSizeX )
|
|
3611
|
+
{
|
|
3612
|
+
this.setScrollLeft( currentScrollLeft - this.charWidth );
|
|
3613
|
+
}
|
|
3593
3614
|
}
|
|
3594
3615
|
|
|
3595
3616
|
cursorToTop( cursor, resetLeft = false ) {
|
|
@@ -3600,30 +3621,40 @@ class CodeEditor {
|
|
|
3600
3621
|
this.restartBlink();
|
|
3601
3622
|
|
|
3602
3623
|
if( resetLeft )
|
|
3624
|
+
{
|
|
3603
3625
|
this.resetCursorPos( CodeEditor.CURSOR_LEFT, cursor );
|
|
3626
|
+
}
|
|
3604
3627
|
|
|
3605
|
-
|
|
3606
|
-
|
|
3607
|
-
|
|
3608
|
-
|
|
3609
|
-
|
|
3628
|
+
const currentScrollTop = this.getScrollTop();
|
|
3629
|
+
var firstLine = ( currentScrollTop / this.lineHeight )|0;
|
|
3630
|
+
if( (cursor.line - 1) < firstLine )
|
|
3631
|
+
{
|
|
3632
|
+
this.setScrollTop( currentScrollTop - this.lineHeight );
|
|
3633
|
+
}
|
|
3610
3634
|
}
|
|
3611
3635
|
|
|
3612
3636
|
cursorToBottom( cursor, resetLeft = false ) {
|
|
3613
3637
|
|
|
3614
3638
|
cursor._top += this.lineHeight;
|
|
3615
|
-
cursor.style.top =
|
|
3639
|
+
cursor.style.top = `calc(${ cursor._top }px)`;
|
|
3616
3640
|
|
|
3617
3641
|
this.restartBlink();
|
|
3618
3642
|
|
|
3619
3643
|
if( resetLeft )
|
|
3644
|
+
{
|
|
3620
3645
|
this.resetCursorPos( CodeEditor.CURSOR_LEFT, cursor );
|
|
3646
|
+
}
|
|
3621
3647
|
|
|
3622
|
-
|
|
3623
|
-
|
|
3624
|
-
|
|
3625
|
-
|
|
3626
|
-
|
|
3648
|
+
const currentScrollTop = this.getScrollTop();
|
|
3649
|
+
const tabsHeight = this.tabs.root.getBoundingClientRect().height;
|
|
3650
|
+
const infoPanelHeight = this.skipInfo ? 0 : this.infoPanel.root.getBoundingClientRect().height;
|
|
3651
|
+
const scrollerHeight = this.codeScroller.offsetHeight;
|
|
3652
|
+
|
|
3653
|
+
var lastLine = ( ( scrollerHeight - tabsHeight - infoPanelHeight + currentScrollTop ) / this.lineHeight )|0;
|
|
3654
|
+
if( cursor.line >= lastLine )
|
|
3655
|
+
{
|
|
3656
|
+
this.setScrollTop( currentScrollTop + this.lineHeight );
|
|
3657
|
+
}
|
|
3627
3658
|
}
|
|
3628
3659
|
|
|
3629
3660
|
cursorToString( cursor, text, reverse ) {
|
|
@@ -3632,7 +3663,9 @@ class CodeEditor {
|
|
|
3632
3663
|
return;
|
|
3633
3664
|
|
|
3634
3665
|
for( let char of text )
|
|
3666
|
+
{
|
|
3635
3667
|
reverse ? this.cursorToLeft( char, cursor ) : this.cursorToRight( char, cursor );
|
|
3668
|
+
}
|
|
3636
3669
|
}
|
|
3637
3670
|
|
|
3638
3671
|
cursorToPosition( cursor, position ) {
|
|
@@ -3756,9 +3789,8 @@ class CodeEditor {
|
|
|
3756
3789
|
}
|
|
3757
3790
|
|
|
3758
3791
|
_removeSpaces( cursor ) {
|
|
3759
|
-
|
|
3760
|
-
// Remove indentation
|
|
3761
3792
|
const lidx = cursor.line;
|
|
3793
|
+
// Remove indentation
|
|
3762
3794
|
let lineStart = firstNonspaceIndex( this.code.lines[ lidx ] );
|
|
3763
3795
|
|
|
3764
3796
|
// Nothing to remove... we are at the start of the line
|
|
@@ -3792,29 +3824,29 @@ class CodeEditor {
|
|
|
3792
3824
|
}
|
|
3793
3825
|
|
|
3794
3826
|
getScrollLeft() {
|
|
3795
|
-
|
|
3796
3827
|
if( !this.codeScroller ) return 0;
|
|
3797
3828
|
return this.codeScroller.scrollLeft;
|
|
3798
3829
|
}
|
|
3799
3830
|
|
|
3800
3831
|
getScrollTop() {
|
|
3801
|
-
|
|
3802
3832
|
if( !this.codeScroller ) return 0;
|
|
3803
3833
|
return this.codeScroller.scrollTop;
|
|
3804
3834
|
}
|
|
3805
3835
|
|
|
3806
3836
|
setScrollLeft( value ) {
|
|
3807
|
-
|
|
3808
3837
|
if( !this.codeScroller ) return;
|
|
3809
|
-
|
|
3810
|
-
|
|
3838
|
+
doAsync( () => {
|
|
3839
|
+
this.codeScroller.scrollLeft = value;
|
|
3840
|
+
this.setScrollBarValue( 'horizontal', 0 );
|
|
3841
|
+
}, 20 );
|
|
3811
3842
|
}
|
|
3812
3843
|
|
|
3813
3844
|
setScrollTop( value ) {
|
|
3814
|
-
|
|
3815
3845
|
if( !this.codeScroller ) return;
|
|
3816
|
-
|
|
3817
|
-
|
|
3846
|
+
doAsync( () => {
|
|
3847
|
+
this.codeScroller.scrollTop = value;
|
|
3848
|
+
this.setScrollBarValue( 'vertical' );
|
|
3849
|
+
}, 20 );
|
|
3818
3850
|
}
|
|
3819
3851
|
|
|
3820
3852
|
resize( pMaxLength, onResize ) {
|
|
@@ -3824,12 +3856,15 @@ class CodeEditor {
|
|
|
3824
3856
|
// Update max viewport
|
|
3825
3857
|
const maxLineLength = pMaxLength ?? this.getMaxLineLength();
|
|
3826
3858
|
const scrollWidth = maxLineLength * this.charWidth + CodeEditor.LINE_GUTTER_WIDTH;
|
|
3859
|
+
|
|
3860
|
+
const tabsHeight = this.tabs.root.getBoundingClientRect().height;
|
|
3861
|
+
const infoPanelHeight = this.skipInfo ? 0 : this.infoPanel.root.getBoundingClientRect().height;
|
|
3827
3862
|
const scrollHeight = this.code.lines.length * this.lineHeight;
|
|
3828
3863
|
|
|
3829
3864
|
this._lastMaxLineLength = maxLineLength;
|
|
3830
3865
|
|
|
3831
3866
|
this.codeSizer.style.minWidth = scrollWidth + "px";
|
|
3832
|
-
this.codeSizer.style.minHeight = scrollHeight + "px";
|
|
3867
|
+
this.codeSizer.style.minHeight = ( scrollHeight + tabsHeight + infoPanelHeight ) + "px";
|
|
3833
3868
|
|
|
3834
3869
|
this.resizeScrollBars();
|
|
3835
3870
|
|
|
@@ -190,19 +190,24 @@ function MAKE_CODE( text, language = "js" )
|
|
|
190
190
|
|
|
191
191
|
window.MAKE_CODE = MAKE_CODE;
|
|
192
192
|
|
|
193
|
-
function MAKE_LIST( list, type )
|
|
193
|
+
function MAKE_LIST( list, type, target )
|
|
194
194
|
{
|
|
195
195
|
const validTypes = [ 'bullet', 'numbered' ];
|
|
196
196
|
console.assert( list && list.length > 0 && validTypes.includes(type), "Invalid list type or empty list" + type );
|
|
197
197
|
const typeString = type == 'bullet' ? 'ul' : 'ol';
|
|
198
198
|
let ul = document.createElement( typeString );
|
|
199
|
+
target = target ?? mainContainer;
|
|
200
|
+
target.appendChild( ul );
|
|
199
201
|
for( var el of list ) {
|
|
202
|
+
if( el.constructor === Array ) {
|
|
203
|
+
MAKE_LIST( el, type, ul );
|
|
204
|
+
return;
|
|
205
|
+
}
|
|
200
206
|
let li = document.createElement( 'li' );
|
|
201
207
|
li.className = "leading-loose";
|
|
202
208
|
li.innerHTML = el;
|
|
203
209
|
ul.appendChild( li );
|
|
204
210
|
}
|
|
205
|
-
mainContainer.appendChild( ul );
|
|
206
211
|
}
|
|
207
212
|
|
|
208
213
|
function MAKE_BULLET_LIST( list )
|
|
@@ -316,7 +321,9 @@ window.INLINE_LINK = INLINE_LINK;
|
|
|
316
321
|
function INLINE_PAGE( string, page )
|
|
317
322
|
{
|
|
318
323
|
console.assert(string && page);
|
|
319
|
-
|
|
324
|
+
const startPage = page.replace(".html", "");
|
|
325
|
+
const tabName = window.setPath( startPage );
|
|
326
|
+
return `<a onclick="loadPage('${ page }', true, '${ tabName }')">${ string }</a>`;
|
|
320
327
|
}
|
|
321
328
|
|
|
322
329
|
window.INLINE_PAGE = INLINE_PAGE;
|
|
@@ -4,7 +4,7 @@ if(!LX) {
|
|
|
4
4
|
throw("lexgui.js missing!");
|
|
5
5
|
}
|
|
6
6
|
|
|
7
|
-
LX.
|
|
7
|
+
LX.extensions.push( 'ImUI' );
|
|
8
8
|
|
|
9
9
|
function swapElements (obj, a, b) {
|
|
10
10
|
[obj[a], obj[b]] = [obj[b], obj[a]];
|
|
@@ -49,9 +49,9 @@ class ImUI {
|
|
|
49
49
|
// },
|
|
50
50
|
// );
|
|
51
51
|
|
|
52
|
-
//
|
|
52
|
+
// Components
|
|
53
53
|
|
|
54
|
-
this.
|
|
54
|
+
this.components = { };
|
|
55
55
|
|
|
56
56
|
// Mouse state
|
|
57
57
|
|
|
@@ -157,10 +157,10 @@ class ImUI {
|
|
|
157
157
|
|
|
158
158
|
// Store slider value
|
|
159
159
|
|
|
160
|
-
if(!this.
|
|
161
|
-
this.
|
|
160
|
+
if(!this.components[ text ])
|
|
161
|
+
this.components[ text ] = { value: value };
|
|
162
162
|
else
|
|
163
|
-
value = this.
|
|
163
|
+
value = this.components[ text ].value;
|
|
164
164
|
|
|
165
165
|
// Element properties
|
|
166
166
|
|
|
@@ -196,7 +196,7 @@ class ImUI {
|
|
|
196
196
|
if(active)
|
|
197
197
|
{
|
|
198
198
|
value = LX.clamp((this.mousePosition.x - min) / (max - min), 0.0, 1.0);
|
|
199
|
-
this.
|
|
199
|
+
this.components[ text ].value = value;
|
|
200
200
|
}
|
|
201
201
|
|
|
202
202
|
let valueSize = new LX.vec2( fullSize.x * value, size.y );
|
|
@@ -240,10 +240,14 @@ class ImUI {
|
|
|
240
240
|
|
|
241
241
|
// Store slider value
|
|
242
242
|
|
|
243
|
-
if(!this.
|
|
244
|
-
|
|
243
|
+
if( !this.components[ text ] )
|
|
244
|
+
{
|
|
245
|
+
this.components[ text ] = { value: value };
|
|
246
|
+
}
|
|
245
247
|
else
|
|
246
|
-
|
|
248
|
+
{
|
|
249
|
+
value = this.components[ text ].value;
|
|
250
|
+
}
|
|
247
251
|
|
|
248
252
|
// Element properties
|
|
249
253
|
|
|
@@ -280,8 +284,11 @@ class ImUI {
|
|
|
280
284
|
if( pressed )
|
|
281
285
|
{
|
|
282
286
|
value = !value;
|
|
283
|
-
this.
|
|
284
|
-
if(
|
|
287
|
+
this.components[ text ].value = value;
|
|
288
|
+
if( callback )
|
|
289
|
+
{
|
|
290
|
+
callback( value );
|
|
291
|
+
}
|
|
285
292
|
}
|
|
286
293
|
|
|
287
294
|
ctx.fillStyle = value ? (active ? "#ddd" : (hovered ? "#6074e7" : "#3e57e4")) :
|