@opentui/core 0.1.14 → 0.1.15
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/3d.js +3 -3
- package/3d.js.map +3 -3
- package/Renderable.d.ts +20 -9
- package/buffer.d.ts +5 -27
- package/console.d.ts +1 -1
- package/{index-rv93tneq.js → index-sw194bbj.js} +489 -766
- package/index-sw194bbj.js.map +36 -0
- package/index.js +856 -47
- package/index.js.map +8 -5
- package/lib/selection.d.ts +31 -38
- package/lib/styled-text.d.ts +0 -3
- package/package.json +7 -7
- package/renderables/ASCIIFont.d.ts +4 -2
- package/renderables/ScrollBar.d.ts +77 -0
- package/renderables/ScrollBox.d.ts +82 -0
- package/renderables/Slider.d.ts +31 -0
- package/renderables/Text.d.ts +9 -5
- package/renderables/index.d.ts +2 -0
- package/renderer.d.ts +8 -5
- package/text-buffer.d.ts +9 -10
- package/types.d.ts +23 -12
- package/zig.d.ts +13 -23
- package/index-rv93tneq.js.map +0 -36
package/index.js
CHANGED
|
@@ -27,7 +27,6 @@ import {
|
|
|
27
27
|
TerminalConsole,
|
|
28
28
|
TextAttributes,
|
|
29
29
|
TextBuffer,
|
|
30
|
-
TextSelectionHelper,
|
|
31
30
|
TrackedNode,
|
|
32
31
|
bg,
|
|
33
32
|
bgBlack,
|
|
@@ -52,6 +51,7 @@ import {
|
|
|
52
51
|
brightWhite,
|
|
53
52
|
brightYellow,
|
|
54
53
|
capture,
|
|
54
|
+
convertGlobalToLocalSelection,
|
|
55
55
|
coordinateToCharacterIndex,
|
|
56
56
|
createCliRenderer,
|
|
57
57
|
createTextAttributes,
|
|
@@ -79,6 +79,7 @@ import {
|
|
|
79
79
|
isPaddingType,
|
|
80
80
|
isPositionType,
|
|
81
81
|
isPositionTypeType,
|
|
82
|
+
isRenderable,
|
|
82
83
|
isSizeType,
|
|
83
84
|
isVNode,
|
|
84
85
|
isValidPercentage,
|
|
@@ -117,7 +118,7 @@ import {
|
|
|
117
118
|
white,
|
|
118
119
|
wrapWithDelegates,
|
|
119
120
|
yellow
|
|
120
|
-
} from "./index-
|
|
121
|
+
} from "./index-sw194bbj.js";
|
|
121
122
|
// src/post/filters.ts
|
|
122
123
|
function applyScanlines(buffer, strength = 0.8, step = 2) {
|
|
123
124
|
const width = buffer.width;
|
|
@@ -1446,15 +1447,14 @@ class FrameBufferRenderable extends Renderable {
|
|
|
1446
1447
|
// src/renderables/Text.ts
|
|
1447
1448
|
class TextRenderable extends Renderable {
|
|
1448
1449
|
selectable = true;
|
|
1449
|
-
_text
|
|
1450
|
+
_text;
|
|
1450
1451
|
_defaultFg;
|
|
1451
1452
|
_defaultBg;
|
|
1452
1453
|
_defaultAttributes;
|
|
1453
1454
|
_selectionBg;
|
|
1454
1455
|
_selectionFg;
|
|
1455
|
-
|
|
1456
|
+
lastLocalSelection = null;
|
|
1456
1457
|
textBuffer;
|
|
1457
|
-
_plainText = "";
|
|
1458
1458
|
_lineInfo = { lineStarts: [], lineWidths: [] };
|
|
1459
1459
|
_defaultOptions = {
|
|
1460
1460
|
content: "",
|
|
@@ -1467,9 +1467,9 @@ class TextRenderable extends Renderable {
|
|
|
1467
1467
|
};
|
|
1468
1468
|
constructor(ctx, options) {
|
|
1469
1469
|
super(ctx, options);
|
|
1470
|
-
this.selectionHelper = new TextSelectionHelper(() => this.x, () => this.y, () => this._plainText.length, () => this._lineInfo);
|
|
1471
1470
|
const content = options.content ?? this._defaultOptions.content;
|
|
1472
|
-
|
|
1471
|
+
const styledText = typeof content === "string" ? stringToStyledText(content) : content;
|
|
1472
|
+
this._text = styledText;
|
|
1473
1473
|
this._defaultFg = parseColor(options.fg ?? this._defaultOptions.fg);
|
|
1474
1474
|
this._defaultBg = parseColor(options.bg ?? this._defaultOptions.bg);
|
|
1475
1475
|
this._defaultAttributes = options.attributes ?? this._defaultOptions.attributes;
|
|
@@ -1481,14 +1481,15 @@ class TextRenderable extends Renderable {
|
|
|
1481
1481
|
this.textBuffer.setDefaultBg(this._defaultBg);
|
|
1482
1482
|
this.textBuffer.setDefaultAttributes(this._defaultAttributes);
|
|
1483
1483
|
this.setupMeasureFunc();
|
|
1484
|
-
this.updateTextInfo();
|
|
1484
|
+
this.updateTextInfo(styledText);
|
|
1485
1485
|
}
|
|
1486
1486
|
get content() {
|
|
1487
1487
|
return this._text;
|
|
1488
1488
|
}
|
|
1489
1489
|
set content(value) {
|
|
1490
|
-
|
|
1491
|
-
this.
|
|
1490
|
+
const styledText = typeof value === "string" ? stringToStyledText(value) : value;
|
|
1491
|
+
this._text = styledText;
|
|
1492
|
+
this.updateTextInfo(styledText);
|
|
1492
1493
|
}
|
|
1493
1494
|
get fg() {
|
|
1494
1495
|
return this._defaultFg;
|
|
@@ -1508,7 +1509,9 @@ class TextRenderable extends Renderable {
|
|
|
1508
1509
|
const newColor = value ? parseColor(value) : this._defaultOptions.selectionBg;
|
|
1509
1510
|
if (this._selectionBg !== newColor) {
|
|
1510
1511
|
this._selectionBg = newColor;
|
|
1511
|
-
this.
|
|
1512
|
+
if (this.lastLocalSelection) {
|
|
1513
|
+
this.updateLocalSelection(this.lastLocalSelection);
|
|
1514
|
+
}
|
|
1512
1515
|
this.requestRender();
|
|
1513
1516
|
}
|
|
1514
1517
|
}
|
|
@@ -1519,7 +1522,9 @@ class TextRenderable extends Renderable {
|
|
|
1519
1522
|
const newColor = value ? parseColor(value) : this._defaultOptions.selectionFg;
|
|
1520
1523
|
if (this._selectionFg !== newColor) {
|
|
1521
1524
|
this._selectionFg = newColor;
|
|
1522
|
-
this.
|
|
1525
|
+
if (this.lastLocalSelection) {
|
|
1526
|
+
this.updateLocalSelection(this.lastLocalSelection);
|
|
1527
|
+
}
|
|
1523
1528
|
this.requestRender();
|
|
1524
1529
|
}
|
|
1525
1530
|
}
|
|
@@ -1545,29 +1550,30 @@ class TextRenderable extends Renderable {
|
|
|
1545
1550
|
}
|
|
1546
1551
|
}
|
|
1547
1552
|
onResize(width, height) {
|
|
1548
|
-
|
|
1549
|
-
|
|
1550
|
-
|
|
1551
|
-
|
|
1553
|
+
if (this.lastLocalSelection) {
|
|
1554
|
+
const changed = this.updateLocalSelection(this.lastLocalSelection);
|
|
1555
|
+
if (changed) {
|
|
1556
|
+
this.requestRender();
|
|
1557
|
+
}
|
|
1552
1558
|
}
|
|
1553
1559
|
}
|
|
1554
|
-
|
|
1555
|
-
|
|
1556
|
-
|
|
1557
|
-
|
|
1558
|
-
} else {
|
|
1559
|
-
this.textBuffer.resetSelection();
|
|
1560
|
+
updateLocalSelection(localSelection) {
|
|
1561
|
+
if (!localSelection?.isActive) {
|
|
1562
|
+
this.textBuffer.resetLocalSelection();
|
|
1563
|
+
return true;
|
|
1560
1564
|
}
|
|
1565
|
+
return this.textBuffer.setLocalSelection(localSelection.anchorX, localSelection.anchorY, localSelection.focusX, localSelection.focusY, this._selectionBg, this._selectionFg);
|
|
1561
1566
|
}
|
|
1562
|
-
updateTextInfo() {
|
|
1563
|
-
this.
|
|
1564
|
-
this.updateTextBuffer();
|
|
1567
|
+
updateTextInfo(styledText) {
|
|
1568
|
+
this.updateTextBuffer(styledText);
|
|
1565
1569
|
const lineInfo = this.textBuffer.lineInfo;
|
|
1566
1570
|
this._lineInfo.lineStarts = lineInfo.lineStarts;
|
|
1567
1571
|
this._lineInfo.lineWidths = lineInfo.lineWidths;
|
|
1568
|
-
|
|
1569
|
-
|
|
1570
|
-
|
|
1572
|
+
if (this.lastLocalSelection) {
|
|
1573
|
+
const changed = this.updateLocalSelection(this.lastLocalSelection);
|
|
1574
|
+
if (changed) {
|
|
1575
|
+
this.requestRender();
|
|
1576
|
+
}
|
|
1571
1577
|
}
|
|
1572
1578
|
this.layoutNode.yogaNode.markDirty();
|
|
1573
1579
|
this.requestRender();
|
|
@@ -1596,27 +1602,32 @@ class TextRenderable extends Renderable {
|
|
|
1596
1602
|
this.layoutNode.yogaNode.setMeasureFunc(measureFunc);
|
|
1597
1603
|
}
|
|
1598
1604
|
shouldStartSelection(x, y) {
|
|
1599
|
-
|
|
1605
|
+
if (!this.selectable)
|
|
1606
|
+
return false;
|
|
1607
|
+
const localX = x - this.x;
|
|
1608
|
+
const localY = y - this.y;
|
|
1609
|
+
return localX >= 0 && localX < this.width && localY >= 0 && localY < this.height;
|
|
1600
1610
|
}
|
|
1601
1611
|
onSelectionChanged(selection) {
|
|
1602
|
-
const
|
|
1612
|
+
const localSelection = convertGlobalToLocalSelection(selection, this.x, this.y);
|
|
1613
|
+
this.lastLocalSelection = localSelection;
|
|
1614
|
+
const changed = this.updateLocalSelection(localSelection);
|
|
1603
1615
|
if (changed) {
|
|
1604
|
-
this.syncSelectionToTextBuffer();
|
|
1605
1616
|
this.requestRender();
|
|
1606
1617
|
}
|
|
1607
|
-
return this.
|
|
1618
|
+
return this.hasSelection();
|
|
1608
1619
|
}
|
|
1609
1620
|
getSelectedText() {
|
|
1610
|
-
|
|
1611
|
-
if (!selection)
|
|
1612
|
-
return "";
|
|
1613
|
-
return this._plainText.slice(selection.start, selection.end);
|
|
1621
|
+
return this.textBuffer.getSelectedText();
|
|
1614
1622
|
}
|
|
1615
1623
|
hasSelection() {
|
|
1616
|
-
return this.
|
|
1624
|
+
return this.textBuffer.hasSelection();
|
|
1617
1625
|
}
|
|
1618
|
-
|
|
1619
|
-
this.textBuffer.
|
|
1626
|
+
getSelection() {
|
|
1627
|
+
return this.textBuffer.getSelection();
|
|
1628
|
+
}
|
|
1629
|
+
updateTextBuffer(styledText) {
|
|
1630
|
+
this.textBuffer.setStyledText(styledText);
|
|
1620
1631
|
}
|
|
1621
1632
|
renderSelf(buffer) {
|
|
1622
1633
|
if (this.textBuffer.ptr) {
|
|
@@ -1643,6 +1654,7 @@ class ASCIIFontRenderable extends FrameBufferRenderable {
|
|
|
1643
1654
|
_bg;
|
|
1644
1655
|
_selectionBg;
|
|
1645
1656
|
_selectionFg;
|
|
1657
|
+
lastLocalSelection = null;
|
|
1646
1658
|
selectionHelper;
|
|
1647
1659
|
constructor(ctx, options) {
|
|
1648
1660
|
const font = options.font || "tiny";
|
|
@@ -1661,7 +1673,7 @@ class ASCIIFontRenderable extends FrameBufferRenderable {
|
|
|
1661
1673
|
this._selectionBg = options.selectionBg ? parseColor(options.selectionBg) : undefined;
|
|
1662
1674
|
this._selectionFg = options.selectionFg ? parseColor(options.selectionFg) : undefined;
|
|
1663
1675
|
this.selectable = options.selectable ?? true;
|
|
1664
|
-
this.selectionHelper = new ASCIIFontSelectionHelper(() => this.
|
|
1676
|
+
this.selectionHelper = new ASCIIFontSelectionHelper(() => this._text, () => this._font);
|
|
1665
1677
|
this.renderFontToBuffer();
|
|
1666
1678
|
}
|
|
1667
1679
|
get text() {
|
|
@@ -1670,7 +1682,9 @@ class ASCIIFontRenderable extends FrameBufferRenderable {
|
|
|
1670
1682
|
set text(value) {
|
|
1671
1683
|
this._text = value;
|
|
1672
1684
|
this.updateDimensions();
|
|
1673
|
-
|
|
1685
|
+
if (this.lastLocalSelection) {
|
|
1686
|
+
this.selectionHelper.onLocalSelectionChanged(this.lastLocalSelection, this.width, this.height);
|
|
1687
|
+
}
|
|
1674
1688
|
this.renderFontToBuffer();
|
|
1675
1689
|
this.requestRender();
|
|
1676
1690
|
}
|
|
@@ -1680,7 +1694,9 @@ class ASCIIFontRenderable extends FrameBufferRenderable {
|
|
|
1680
1694
|
set font(value) {
|
|
1681
1695
|
this._font = value;
|
|
1682
1696
|
this.updateDimensions();
|
|
1683
|
-
|
|
1697
|
+
if (this.lastLocalSelection) {
|
|
1698
|
+
this.selectionHelper.onLocalSelectionChanged(this.lastLocalSelection, this.width, this.height);
|
|
1699
|
+
}
|
|
1684
1700
|
this.renderFontToBuffer();
|
|
1685
1701
|
this.requestRender();
|
|
1686
1702
|
}
|
|
@@ -1710,15 +1726,19 @@ class ASCIIFontRenderable extends FrameBufferRenderable {
|
|
|
1710
1726
|
this.height = measurements.height;
|
|
1711
1727
|
}
|
|
1712
1728
|
shouldStartSelection(x, y) {
|
|
1713
|
-
|
|
1729
|
+
const localX = x - this.x;
|
|
1730
|
+
const localY = y - this.y;
|
|
1731
|
+
return this.selectionHelper.shouldStartSelection(localX, localY, this.width, this.height);
|
|
1714
1732
|
}
|
|
1715
1733
|
onSelectionChanged(selection) {
|
|
1716
|
-
const
|
|
1734
|
+
const localSelection = convertGlobalToLocalSelection(selection, this.x, this.y);
|
|
1735
|
+
this.lastLocalSelection = localSelection;
|
|
1736
|
+
const changed = this.selectionHelper.onLocalSelectionChanged(localSelection, this.width, this.height);
|
|
1717
1737
|
if (changed) {
|
|
1718
1738
|
this.renderFontToBuffer();
|
|
1719
1739
|
this.requestRender();
|
|
1720
1740
|
}
|
|
1721
|
-
return
|
|
1741
|
+
return changed;
|
|
1722
1742
|
}
|
|
1723
1743
|
getSelectedText() {
|
|
1724
1744
|
const selection = this.selectionHelper.getSelection();
|
|
@@ -2674,6 +2694,791 @@ class TabSelectRenderable extends Renderable {
|
|
|
2674
2694
|
this.requestRender();
|
|
2675
2695
|
}
|
|
2676
2696
|
}
|
|
2697
|
+
// src/renderables/Slider.ts
|
|
2698
|
+
var defaultThumbBackgroundColor = RGBA.fromHex("#9a9ea3");
|
|
2699
|
+
var defaultTrackBackgroundColor = RGBA.fromHex("#252527");
|
|
2700
|
+
|
|
2701
|
+
class SliderRenderable extends Renderable {
|
|
2702
|
+
orientation;
|
|
2703
|
+
_thumbSize;
|
|
2704
|
+
_thumbPosition;
|
|
2705
|
+
_backgroundColor;
|
|
2706
|
+
_foregroundColor;
|
|
2707
|
+
_onChange;
|
|
2708
|
+
constructor(ctx, options) {
|
|
2709
|
+
super(ctx, options);
|
|
2710
|
+
this.orientation = options.orientation;
|
|
2711
|
+
this._thumbSize = options.thumbSize ?? 1;
|
|
2712
|
+
this._thumbPosition = options.thumbPosition ?? 0;
|
|
2713
|
+
this._onChange = options.onChange;
|
|
2714
|
+
this._backgroundColor = options.backgroundColor ? parseColor(options.backgroundColor) : defaultTrackBackgroundColor;
|
|
2715
|
+
this._foregroundColor = options.foregroundColor ? parseColor(options.foregroundColor) : defaultThumbBackgroundColor;
|
|
2716
|
+
this.setupMouseHandling();
|
|
2717
|
+
}
|
|
2718
|
+
get thumbSize() {
|
|
2719
|
+
return this._thumbSize;
|
|
2720
|
+
}
|
|
2721
|
+
set thumbSize(value) {
|
|
2722
|
+
const clamped = Math.max(1, Math.min(value, this.orientation === "vertical" ? this.height : this.width));
|
|
2723
|
+
if (clamped !== this._thumbSize) {
|
|
2724
|
+
this._thumbSize = clamped;
|
|
2725
|
+
this.requestRender();
|
|
2726
|
+
}
|
|
2727
|
+
}
|
|
2728
|
+
get thumbPosition() {
|
|
2729
|
+
return this._thumbPosition;
|
|
2730
|
+
}
|
|
2731
|
+
set thumbPosition(value) {
|
|
2732
|
+
const clamped = Math.max(0, Math.min(1, value));
|
|
2733
|
+
if (clamped !== this._thumbPosition) {
|
|
2734
|
+
this._thumbPosition = clamped;
|
|
2735
|
+
this._onChange?.(clamped);
|
|
2736
|
+
this.emit("change", { position: clamped });
|
|
2737
|
+
this.requestRender();
|
|
2738
|
+
}
|
|
2739
|
+
}
|
|
2740
|
+
get backgroundColor() {
|
|
2741
|
+
return this._backgroundColor;
|
|
2742
|
+
}
|
|
2743
|
+
set backgroundColor(value) {
|
|
2744
|
+
this._backgroundColor = parseColor(value);
|
|
2745
|
+
this.requestRender();
|
|
2746
|
+
}
|
|
2747
|
+
get foregroundColor() {
|
|
2748
|
+
return this._foregroundColor;
|
|
2749
|
+
}
|
|
2750
|
+
set foregroundColor(value) {
|
|
2751
|
+
this._foregroundColor = parseColor(value);
|
|
2752
|
+
this.requestRender();
|
|
2753
|
+
}
|
|
2754
|
+
setupMouseHandling() {
|
|
2755
|
+
let isDragging = false;
|
|
2756
|
+
let relativeStartPos = 0;
|
|
2757
|
+
this.onMouseDown = (event) => {
|
|
2758
|
+
event.stopPropagation();
|
|
2759
|
+
isDragging = true;
|
|
2760
|
+
const thumbRect = this.getThumbRect();
|
|
2761
|
+
const isOnThumb = event.x >= thumbRect.x && event.x < thumbRect.x + thumbRect.width && event.y >= thumbRect.y && event.y < thumbRect.y + thumbRect.height;
|
|
2762
|
+
if (isOnThumb) {
|
|
2763
|
+
relativeStartPos = this.orientation === "vertical" ? event.y - thumbRect.y : event.x - thumbRect.x;
|
|
2764
|
+
} else {
|
|
2765
|
+
relativeStartPos = this.orientation === "vertical" ? thumbRect.height / 2 : thumbRect.width / 2;
|
|
2766
|
+
}
|
|
2767
|
+
this.updatePositionFromMouse(event, relativeStartPos);
|
|
2768
|
+
};
|
|
2769
|
+
this.onMouseDrag = (event) => {
|
|
2770
|
+
if (!isDragging)
|
|
2771
|
+
return;
|
|
2772
|
+
event.stopPropagation();
|
|
2773
|
+
this.updatePositionFromMouse(event, relativeStartPos);
|
|
2774
|
+
};
|
|
2775
|
+
this.onMouseUp = () => {
|
|
2776
|
+
isDragging = false;
|
|
2777
|
+
};
|
|
2778
|
+
}
|
|
2779
|
+
updatePositionFromMouse(event, relativeStartPos) {
|
|
2780
|
+
const trackStart = this.orientation === "vertical" ? this.y : this.x;
|
|
2781
|
+
const trackSize = this.orientation === "vertical" ? this.height : this.width;
|
|
2782
|
+
const mousePos = this.orientation === "vertical" ? event.y : event.x;
|
|
2783
|
+
const thumbStartPos = mousePos - trackStart - relativeStartPos;
|
|
2784
|
+
const maxThumbStartPos = trackSize - this._thumbSize;
|
|
2785
|
+
const clampedThumbStartPos = Math.max(0, Math.min(maxThumbStartPos, thumbStartPos));
|
|
2786
|
+
const newPosition = maxThumbStartPos > 0 ? clampedThumbStartPos / maxThumbStartPos : 0;
|
|
2787
|
+
this.thumbPosition = newPosition;
|
|
2788
|
+
}
|
|
2789
|
+
getThumbPosition() {
|
|
2790
|
+
const trackSize = this.orientation === "vertical" ? this.height : this.width;
|
|
2791
|
+
const maxPos = trackSize - this._thumbSize;
|
|
2792
|
+
return Math.round(this._thumbPosition * maxPos);
|
|
2793
|
+
}
|
|
2794
|
+
getThumbRect() {
|
|
2795
|
+
const thumbPos = this.getThumbPosition();
|
|
2796
|
+
if (this.orientation === "vertical") {
|
|
2797
|
+
return {
|
|
2798
|
+
x: this.x,
|
|
2799
|
+
y: this.y + thumbPos,
|
|
2800
|
+
width: this.width,
|
|
2801
|
+
height: this._thumbSize
|
|
2802
|
+
};
|
|
2803
|
+
} else {
|
|
2804
|
+
return {
|
|
2805
|
+
x: this.x + thumbPos,
|
|
2806
|
+
y: this.y,
|
|
2807
|
+
width: this._thumbSize,
|
|
2808
|
+
height: this.height
|
|
2809
|
+
};
|
|
2810
|
+
}
|
|
2811
|
+
}
|
|
2812
|
+
renderSelf(buffer) {
|
|
2813
|
+
buffer.fillRect(this.x, this.y, this.width, this.height, this._backgroundColor);
|
|
2814
|
+
const thumbRect = this.getThumbRect();
|
|
2815
|
+
buffer.fillRect(thumbRect.x, thumbRect.y, thumbRect.width, thumbRect.height, this._foregroundColor);
|
|
2816
|
+
}
|
|
2817
|
+
}
|
|
2818
|
+
|
|
2819
|
+
// src/renderables/ScrollBar.ts
|
|
2820
|
+
class ScrollBarRenderable extends Renderable {
|
|
2821
|
+
slider;
|
|
2822
|
+
startArrow;
|
|
2823
|
+
endArrow;
|
|
2824
|
+
orientation;
|
|
2825
|
+
focusable = true;
|
|
2826
|
+
_scrollSize = 0;
|
|
2827
|
+
_scrollPosition = 0;
|
|
2828
|
+
_viewportSize = 0;
|
|
2829
|
+
_showArrows = false;
|
|
2830
|
+
_manualVisibility = false;
|
|
2831
|
+
_onChange;
|
|
2832
|
+
scrollStep = null;
|
|
2833
|
+
get visible() {
|
|
2834
|
+
return super.visible;
|
|
2835
|
+
}
|
|
2836
|
+
set visible(value) {
|
|
2837
|
+
this._manualVisibility = true;
|
|
2838
|
+
super.visible = value;
|
|
2839
|
+
}
|
|
2840
|
+
resetVisibilityControl() {
|
|
2841
|
+
this._manualVisibility = false;
|
|
2842
|
+
this.recalculateVisibility();
|
|
2843
|
+
}
|
|
2844
|
+
get scrollSize() {
|
|
2845
|
+
return this._scrollSize;
|
|
2846
|
+
}
|
|
2847
|
+
get scrollPosition() {
|
|
2848
|
+
return this._scrollPosition;
|
|
2849
|
+
}
|
|
2850
|
+
get viewportSize() {
|
|
2851
|
+
return this._viewportSize;
|
|
2852
|
+
}
|
|
2853
|
+
set scrollSize(value) {
|
|
2854
|
+
if (value === this.scrollSize)
|
|
2855
|
+
return;
|
|
2856
|
+
this._scrollSize = value;
|
|
2857
|
+
this.recalculateVisibility();
|
|
2858
|
+
this.scrollPosition = this.scrollPosition;
|
|
2859
|
+
}
|
|
2860
|
+
set scrollPosition(value) {
|
|
2861
|
+
const newPosition = Math.round(Math.min(Math.max(0, value), this.scrollSize - this.viewportSize));
|
|
2862
|
+
if (newPosition !== this._scrollPosition) {
|
|
2863
|
+
this._scrollPosition = newPosition;
|
|
2864
|
+
this.updateSliderFromScrollState();
|
|
2865
|
+
this._onChange?.(newPosition);
|
|
2866
|
+
this.emit("change", { position: newPosition });
|
|
2867
|
+
}
|
|
2868
|
+
}
|
|
2869
|
+
set viewportSize(value) {
|
|
2870
|
+
if (value === this.viewportSize)
|
|
2871
|
+
return;
|
|
2872
|
+
this._viewportSize = value;
|
|
2873
|
+
this.recalculateVisibility();
|
|
2874
|
+
this.scrollPosition = this.scrollPosition;
|
|
2875
|
+
}
|
|
2876
|
+
get showArrows() {
|
|
2877
|
+
return this._showArrows;
|
|
2878
|
+
}
|
|
2879
|
+
set showArrows(value) {
|
|
2880
|
+
if (value === this._showArrows)
|
|
2881
|
+
return;
|
|
2882
|
+
this._showArrows = value;
|
|
2883
|
+
this.startArrow.visible = value;
|
|
2884
|
+
this.endArrow.visible = value;
|
|
2885
|
+
}
|
|
2886
|
+
constructor(ctx, { trackOptions, arrowOptions, orientation, showArrows = false, ...options }) {
|
|
2887
|
+
super(ctx, {
|
|
2888
|
+
flexDirection: orientation === "vertical" ? "column" : "row",
|
|
2889
|
+
alignSelf: "stretch",
|
|
2890
|
+
alignItems: "stretch",
|
|
2891
|
+
...options
|
|
2892
|
+
});
|
|
2893
|
+
this._onChange = options.onChange;
|
|
2894
|
+
this.orientation = orientation;
|
|
2895
|
+
this._showArrows = showArrows;
|
|
2896
|
+
this.slider = new SliderRenderable(ctx, {
|
|
2897
|
+
orientation,
|
|
2898
|
+
onChange: (position) => {
|
|
2899
|
+
const scrollRange = Math.max(0, this._scrollSize - this._viewportSize);
|
|
2900
|
+
this._scrollPosition = Math.round(position * scrollRange);
|
|
2901
|
+
this._onChange?.(this._scrollPosition);
|
|
2902
|
+
this.emit("change", { position: this._scrollPosition });
|
|
2903
|
+
},
|
|
2904
|
+
...orientation === "vertical" ? {
|
|
2905
|
+
width: 2,
|
|
2906
|
+
height: "100%",
|
|
2907
|
+
marginLeft: "auto"
|
|
2908
|
+
} : {
|
|
2909
|
+
width: "100%",
|
|
2910
|
+
height: 1,
|
|
2911
|
+
marginTop: "auto"
|
|
2912
|
+
},
|
|
2913
|
+
flexGrow: 1,
|
|
2914
|
+
flexShrink: 1,
|
|
2915
|
+
...trackOptions
|
|
2916
|
+
});
|
|
2917
|
+
this.updateSliderFromScrollState();
|
|
2918
|
+
const arrowOpts = arrowOptions ? {
|
|
2919
|
+
foregroundColor: arrowOptions.backgroundColor,
|
|
2920
|
+
backgroundColor: arrowOptions.backgroundColor,
|
|
2921
|
+
attributes: arrowOptions.attributes,
|
|
2922
|
+
...arrowOptions
|
|
2923
|
+
} : {};
|
|
2924
|
+
this.startArrow = new ArrowRenderable(ctx, {
|
|
2925
|
+
alignSelf: "center",
|
|
2926
|
+
visible: this.showArrows,
|
|
2927
|
+
direction: this.orientation === "vertical" ? "up" : "left",
|
|
2928
|
+
height: this.orientation === "vertical" ? 1 : 1,
|
|
2929
|
+
...arrowOpts
|
|
2930
|
+
});
|
|
2931
|
+
this.endArrow = new ArrowRenderable(ctx, {
|
|
2932
|
+
alignSelf: "center",
|
|
2933
|
+
visible: this.showArrows,
|
|
2934
|
+
direction: this.orientation === "vertical" ? "down" : "right",
|
|
2935
|
+
height: this.orientation === "vertical" ? 1 : 1,
|
|
2936
|
+
...arrowOpts
|
|
2937
|
+
});
|
|
2938
|
+
this.add(this.startArrow);
|
|
2939
|
+
this.add(this.slider);
|
|
2940
|
+
this.add(this.endArrow);
|
|
2941
|
+
let startArrowMouseTimeout = undefined;
|
|
2942
|
+
let endArrowMouseTimeout = undefined;
|
|
2943
|
+
this.startArrow.onMouseDown = (event) => {
|
|
2944
|
+
event.stopPropagation();
|
|
2945
|
+
this.scrollBy(-0.5, "viewport");
|
|
2946
|
+
startArrowMouseTimeout = setTimeout(() => {
|
|
2947
|
+
this.scrollBy(-0.5, "viewport");
|
|
2948
|
+
startArrowMouseTimeout = setInterval(() => {
|
|
2949
|
+
this.scrollBy(-0.2, "viewport");
|
|
2950
|
+
}, 200);
|
|
2951
|
+
}, 500);
|
|
2952
|
+
};
|
|
2953
|
+
this.startArrow.onMouseUp = (event) => {
|
|
2954
|
+
event.stopPropagation();
|
|
2955
|
+
clearInterval(startArrowMouseTimeout);
|
|
2956
|
+
};
|
|
2957
|
+
this.endArrow.onMouseDown = (event) => {
|
|
2958
|
+
event.stopPropagation();
|
|
2959
|
+
this.scrollBy(0.5, "viewport");
|
|
2960
|
+
endArrowMouseTimeout = setTimeout(() => {
|
|
2961
|
+
this.scrollBy(0.5, "viewport");
|
|
2962
|
+
endArrowMouseTimeout = setInterval(() => {
|
|
2963
|
+
this.scrollBy(0.2, "viewport");
|
|
2964
|
+
}, 200);
|
|
2965
|
+
}, 500);
|
|
2966
|
+
};
|
|
2967
|
+
this.endArrow.onMouseUp = (event) => {
|
|
2968
|
+
event.stopPropagation();
|
|
2969
|
+
clearInterval(endArrowMouseTimeout);
|
|
2970
|
+
};
|
|
2971
|
+
}
|
|
2972
|
+
set arrowOptions(options) {
|
|
2973
|
+
Object.assign(this.startArrow, options);
|
|
2974
|
+
Object.assign(this.endArrow, options);
|
|
2975
|
+
this.requestRender();
|
|
2976
|
+
}
|
|
2977
|
+
set trackOptions(options) {
|
|
2978
|
+
Object.assign(this.slider, options);
|
|
2979
|
+
this.requestRender();
|
|
2980
|
+
}
|
|
2981
|
+
updateSliderFromScrollState() {
|
|
2982
|
+
const trackSize = this.orientation === "vertical" ? this.slider.height : this.slider.width;
|
|
2983
|
+
const scrollRange = Math.max(0, this._scrollSize - this._viewportSize);
|
|
2984
|
+
if (scrollRange === 0) {
|
|
2985
|
+
this.slider.thumbSize = trackSize;
|
|
2986
|
+
this.slider.thumbPosition = 0;
|
|
2987
|
+
} else {
|
|
2988
|
+
const sizeRatio = this._viewportSize / this._scrollSize;
|
|
2989
|
+
this.slider.thumbSize = Math.max(1, Math.round(sizeRatio * trackSize));
|
|
2990
|
+
const positionRatio = this._scrollPosition / scrollRange;
|
|
2991
|
+
this.slider.thumbPosition = Math.max(0, Math.min(1, positionRatio));
|
|
2992
|
+
}
|
|
2993
|
+
}
|
|
2994
|
+
scrollBy(delta, unit = "absolute") {
|
|
2995
|
+
const multiplier = unit === "viewport" ? this.viewportSize : unit === "content" ? this.scrollSize : unit === "step" ? this.scrollStep ?? 1 : 1;
|
|
2996
|
+
const resolvedDelta = multiplier * delta;
|
|
2997
|
+
this.scrollPosition += resolvedDelta;
|
|
2998
|
+
}
|
|
2999
|
+
recalculateVisibility() {
|
|
3000
|
+
if (!this._manualVisibility) {
|
|
3001
|
+
const sizeRatio = this.scrollSize <= this.viewportSize ? 1 : this.viewportSize / this.scrollSize;
|
|
3002
|
+
super.visible = sizeRatio < 1;
|
|
3003
|
+
}
|
|
3004
|
+
}
|
|
3005
|
+
handleKeyPress(key) {
|
|
3006
|
+
const keyName = typeof key === "string" ? key : key.name;
|
|
3007
|
+
switch (keyName) {
|
|
3008
|
+
case "left":
|
|
3009
|
+
case "h":
|
|
3010
|
+
if (this.orientation !== "horizontal")
|
|
3011
|
+
return false;
|
|
3012
|
+
this.scrollBy(-1 / 5, "viewport");
|
|
3013
|
+
return true;
|
|
3014
|
+
case "right":
|
|
3015
|
+
case "l":
|
|
3016
|
+
if (this.orientation !== "horizontal")
|
|
3017
|
+
return false;
|
|
3018
|
+
this.scrollBy(1 / 5, "viewport");
|
|
3019
|
+
return true;
|
|
3020
|
+
case "up":
|
|
3021
|
+
case "k":
|
|
3022
|
+
if (this.orientation !== "vertical")
|
|
3023
|
+
return false;
|
|
3024
|
+
this.scrollBy(-1 / 5, "viewport");
|
|
3025
|
+
return true;
|
|
3026
|
+
case "down":
|
|
3027
|
+
case "j":
|
|
3028
|
+
if (this.orientation !== "vertical")
|
|
3029
|
+
return false;
|
|
3030
|
+
this.scrollBy(1 / 5, "viewport");
|
|
3031
|
+
return true;
|
|
3032
|
+
case "pageup":
|
|
3033
|
+
this.scrollBy(-1 / 2, "viewport");
|
|
3034
|
+
return true;
|
|
3035
|
+
case "pagedown":
|
|
3036
|
+
this.scrollBy(1 / 2, "viewport");
|
|
3037
|
+
return true;
|
|
3038
|
+
case "home":
|
|
3039
|
+
this.scrollBy(-1, "content");
|
|
3040
|
+
return true;
|
|
3041
|
+
case "end":
|
|
3042
|
+
this.scrollBy(1, "content");
|
|
3043
|
+
return true;
|
|
3044
|
+
}
|
|
3045
|
+
return false;
|
|
3046
|
+
}
|
|
3047
|
+
}
|
|
3048
|
+
|
|
3049
|
+
class ArrowRenderable extends Renderable {
|
|
3050
|
+
_direction;
|
|
3051
|
+
_foregroundColor;
|
|
3052
|
+
_backgroundColor;
|
|
3053
|
+
_attributes;
|
|
3054
|
+
_arrowChars;
|
|
3055
|
+
constructor(ctx, options) {
|
|
3056
|
+
super(ctx, options);
|
|
3057
|
+
this._direction = options.direction;
|
|
3058
|
+
this._foregroundColor = options.foregroundColor ? parseColor(options.foregroundColor) : RGBA.fromValues(1, 1, 1, 1);
|
|
3059
|
+
this._backgroundColor = options.backgroundColor ? parseColor(options.backgroundColor) : RGBA.fromValues(0, 0, 0, 0);
|
|
3060
|
+
this._attributes = options.attributes ?? 0;
|
|
3061
|
+
this._arrowChars = {
|
|
3062
|
+
up: "\u25E2\u25E3",
|
|
3063
|
+
down: "\u25E5\u25E4",
|
|
3064
|
+
left: " \u25C0 ",
|
|
3065
|
+
right: " \u25B6 ",
|
|
3066
|
+
...options.arrowChars
|
|
3067
|
+
};
|
|
3068
|
+
if (!options.width) {
|
|
3069
|
+
this.width = Bun.stringWidth(this.getArrowChar());
|
|
3070
|
+
}
|
|
3071
|
+
}
|
|
3072
|
+
get direction() {
|
|
3073
|
+
return this._direction;
|
|
3074
|
+
}
|
|
3075
|
+
set direction(value) {
|
|
3076
|
+
if (this._direction !== value) {
|
|
3077
|
+
this._direction = value;
|
|
3078
|
+
this.requestRender();
|
|
3079
|
+
}
|
|
3080
|
+
}
|
|
3081
|
+
get foregroundColor() {
|
|
3082
|
+
return this._foregroundColor;
|
|
3083
|
+
}
|
|
3084
|
+
set foregroundColor(value) {
|
|
3085
|
+
if (this._foregroundColor !== value) {
|
|
3086
|
+
this._foregroundColor = parseColor(value);
|
|
3087
|
+
this.requestRender();
|
|
3088
|
+
}
|
|
3089
|
+
}
|
|
3090
|
+
get backgroundColor() {
|
|
3091
|
+
return this._backgroundColor;
|
|
3092
|
+
}
|
|
3093
|
+
set backgroundColor(value) {
|
|
3094
|
+
if (this._backgroundColor !== value) {
|
|
3095
|
+
this._backgroundColor = parseColor(value);
|
|
3096
|
+
this.requestRender();
|
|
3097
|
+
}
|
|
3098
|
+
}
|
|
3099
|
+
get attributes() {
|
|
3100
|
+
return this._attributes;
|
|
3101
|
+
}
|
|
3102
|
+
set attributes(value) {
|
|
3103
|
+
if (this._attributes !== value) {
|
|
3104
|
+
this._attributes = value;
|
|
3105
|
+
this.requestRender();
|
|
3106
|
+
}
|
|
3107
|
+
}
|
|
3108
|
+
set arrowChars(value) {
|
|
3109
|
+
this._arrowChars = {
|
|
3110
|
+
...this._arrowChars,
|
|
3111
|
+
...value
|
|
3112
|
+
};
|
|
3113
|
+
this.requestRender();
|
|
3114
|
+
}
|
|
3115
|
+
renderSelf(buffer) {
|
|
3116
|
+
const char = this.getArrowChar();
|
|
3117
|
+
buffer.drawText(char, this.x, this.y, this._foregroundColor, this._backgroundColor, this._attributes);
|
|
3118
|
+
}
|
|
3119
|
+
getArrowChar() {
|
|
3120
|
+
switch (this._direction) {
|
|
3121
|
+
case "up":
|
|
3122
|
+
return this._arrowChars.up;
|
|
3123
|
+
case "down":
|
|
3124
|
+
return this._arrowChars.down;
|
|
3125
|
+
case "left":
|
|
3126
|
+
return this._arrowChars.left;
|
|
3127
|
+
case "right":
|
|
3128
|
+
return this._arrowChars.right;
|
|
3129
|
+
default:
|
|
3130
|
+
return "?";
|
|
3131
|
+
}
|
|
3132
|
+
}
|
|
3133
|
+
}
|
|
3134
|
+
|
|
3135
|
+
// src/renderables/ScrollBox.ts
|
|
3136
|
+
class ContentRenderable extends BoxRenderable {
|
|
3137
|
+
viewport;
|
|
3138
|
+
constructor(ctx, viewport, options) {
|
|
3139
|
+
super(ctx, options);
|
|
3140
|
+
this.viewport = viewport;
|
|
3141
|
+
}
|
|
3142
|
+
_getChildren() {
|
|
3143
|
+
return this.getChildrenInViewport(this.viewport);
|
|
3144
|
+
}
|
|
3145
|
+
}
|
|
3146
|
+
|
|
3147
|
+
class ScrollBoxRenderable extends BoxRenderable {
|
|
3148
|
+
static idCounter = 0;
|
|
3149
|
+
internalId = 0;
|
|
3150
|
+
wrapper;
|
|
3151
|
+
viewport;
|
|
3152
|
+
content;
|
|
3153
|
+
horizontalScrollBar;
|
|
3154
|
+
verticalScrollBar;
|
|
3155
|
+
focusable = true;
|
|
3156
|
+
selectionListener;
|
|
3157
|
+
autoScrollMouseX = 0;
|
|
3158
|
+
autoScrollMouseY = 0;
|
|
3159
|
+
autoScrollThresholdVertical = 3;
|
|
3160
|
+
autoScrollThresholdHorizontal = 3;
|
|
3161
|
+
autoScrollSpeedSlow = 6;
|
|
3162
|
+
autoScrollSpeedMedium = 36;
|
|
3163
|
+
autoScrollSpeedFast = 72;
|
|
3164
|
+
isAutoScrolling = false;
|
|
3165
|
+
cachedAutoScrollSpeed = 3;
|
|
3166
|
+
autoScrollAccumulatorX = 0;
|
|
3167
|
+
autoScrollAccumulatorY = 0;
|
|
3168
|
+
get scrollTop() {
|
|
3169
|
+
return this.verticalScrollBar.scrollPosition;
|
|
3170
|
+
}
|
|
3171
|
+
set scrollTop(value) {
|
|
3172
|
+
this.verticalScrollBar.scrollPosition = value;
|
|
3173
|
+
}
|
|
3174
|
+
get scrollLeft() {
|
|
3175
|
+
return this.horizontalScrollBar.scrollPosition;
|
|
3176
|
+
}
|
|
3177
|
+
set scrollLeft(value) {
|
|
3178
|
+
this.horizontalScrollBar.scrollPosition = value;
|
|
3179
|
+
}
|
|
3180
|
+
get scrollWidth() {
|
|
3181
|
+
return this.horizontalScrollBar.scrollSize;
|
|
3182
|
+
}
|
|
3183
|
+
get scrollHeight() {
|
|
3184
|
+
return this.verticalScrollBar.scrollSize;
|
|
3185
|
+
}
|
|
3186
|
+
constructor(ctx, {
|
|
3187
|
+
wrapperOptions,
|
|
3188
|
+
viewportOptions,
|
|
3189
|
+
contentOptions,
|
|
3190
|
+
rootOptions,
|
|
3191
|
+
scrollbarOptions,
|
|
3192
|
+
verticalScrollbarOptions,
|
|
3193
|
+
horizontalScrollbarOptions,
|
|
3194
|
+
...options
|
|
3195
|
+
}) {
|
|
3196
|
+
super(ctx, {
|
|
3197
|
+
flexShrink: 1,
|
|
3198
|
+
flexGrow: 1,
|
|
3199
|
+
flexDirection: "row",
|
|
3200
|
+
flexWrap: "wrap",
|
|
3201
|
+
alignItems: "stretch",
|
|
3202
|
+
...options,
|
|
3203
|
+
...rootOptions
|
|
3204
|
+
});
|
|
3205
|
+
this.internalId = ScrollBoxRenderable.idCounter++;
|
|
3206
|
+
this.wrapper = new BoxRenderable(ctx, {
|
|
3207
|
+
flexDirection: "column",
|
|
3208
|
+
flexGrow: 1,
|
|
3209
|
+
flexShrink: 1,
|
|
3210
|
+
flexBasis: "auto",
|
|
3211
|
+
maxHeight: "100%",
|
|
3212
|
+
maxWidth: "100%",
|
|
3213
|
+
...wrapperOptions,
|
|
3214
|
+
id: `scroll-box-wrapper-${this.internalId}`
|
|
3215
|
+
});
|
|
3216
|
+
super.add(this.wrapper);
|
|
3217
|
+
this.viewport = new BoxRenderable(ctx, {
|
|
3218
|
+
flexDirection: "column",
|
|
3219
|
+
flexGrow: 1,
|
|
3220
|
+
flexShrink: 1,
|
|
3221
|
+
flexBasis: "auto",
|
|
3222
|
+
maxHeight: "100%",
|
|
3223
|
+
maxWidth: "100%",
|
|
3224
|
+
overflow: "scroll",
|
|
3225
|
+
onSizeChange: () => {
|
|
3226
|
+
this.recalculateBarProps();
|
|
3227
|
+
},
|
|
3228
|
+
...viewportOptions,
|
|
3229
|
+
id: `scroll-box-viewport-${this.internalId}`
|
|
3230
|
+
});
|
|
3231
|
+
this.wrapper.add(this.viewport);
|
|
3232
|
+
this.content = new ContentRenderable(ctx, this.viewport, {
|
|
3233
|
+
alignSelf: "flex-start",
|
|
3234
|
+
onSizeChange: () => {
|
|
3235
|
+
this.recalculateBarProps();
|
|
3236
|
+
},
|
|
3237
|
+
...contentOptions,
|
|
3238
|
+
id: `scroll-box-content-${this.internalId}`
|
|
3239
|
+
});
|
|
3240
|
+
this.viewport.add(this.content);
|
|
3241
|
+
this.verticalScrollBar = new ScrollBarRenderable(ctx, {
|
|
3242
|
+
...scrollbarOptions,
|
|
3243
|
+
...verticalScrollbarOptions,
|
|
3244
|
+
arrowOptions: {
|
|
3245
|
+
...scrollbarOptions?.arrowOptions,
|
|
3246
|
+
...verticalScrollbarOptions?.arrowOptions
|
|
3247
|
+
},
|
|
3248
|
+
id: `scroll-box-vertical-scrollbar-${this.internalId}`,
|
|
3249
|
+
orientation: "vertical",
|
|
3250
|
+
onChange: (position) => {
|
|
3251
|
+
this.content.translateY = -position;
|
|
3252
|
+
}
|
|
3253
|
+
});
|
|
3254
|
+
super.add(this.verticalScrollBar);
|
|
3255
|
+
this.horizontalScrollBar = new ScrollBarRenderable(ctx, {
|
|
3256
|
+
...scrollbarOptions,
|
|
3257
|
+
...horizontalScrollbarOptions,
|
|
3258
|
+
arrowOptions: {
|
|
3259
|
+
...scrollbarOptions?.arrowOptions,
|
|
3260
|
+
...horizontalScrollbarOptions?.arrowOptions
|
|
3261
|
+
},
|
|
3262
|
+
id: `scroll-box-horizontal-scrollbar-${this.internalId}`,
|
|
3263
|
+
orientation: "horizontal",
|
|
3264
|
+
onChange: (position) => {
|
|
3265
|
+
this.content.translateX = -position;
|
|
3266
|
+
}
|
|
3267
|
+
});
|
|
3268
|
+
this.wrapper.add(this.horizontalScrollBar);
|
|
3269
|
+
this.recalculateBarProps();
|
|
3270
|
+
this.selectionListener = () => {
|
|
3271
|
+
const selection = this._ctx.getSelection();
|
|
3272
|
+
if (!selection || !selection.isSelecting) {
|
|
3273
|
+
this.stopAutoScroll();
|
|
3274
|
+
}
|
|
3275
|
+
};
|
|
3276
|
+
this._ctx.on("selection", this.selectionListener);
|
|
3277
|
+
}
|
|
3278
|
+
onUpdate(deltaTime) {
|
|
3279
|
+
this.handleAutoScroll(deltaTime);
|
|
3280
|
+
}
|
|
3281
|
+
scrollBy(delta, unit = "absolute") {
|
|
3282
|
+
if (typeof delta === "number") {
|
|
3283
|
+
this.verticalScrollBar.scrollBy(delta, unit);
|
|
3284
|
+
} else {
|
|
3285
|
+
this.verticalScrollBar.scrollBy(delta.y, unit);
|
|
3286
|
+
this.horizontalScrollBar.scrollBy(delta.x, unit);
|
|
3287
|
+
}
|
|
3288
|
+
}
|
|
3289
|
+
scrollTo(position) {
|
|
3290
|
+
if (typeof position === "number") {
|
|
3291
|
+
this.scrollTop = position;
|
|
3292
|
+
} else {
|
|
3293
|
+
this.scrollTop = position.y;
|
|
3294
|
+
this.scrollLeft = position.x;
|
|
3295
|
+
}
|
|
3296
|
+
}
|
|
3297
|
+
add(obj, index) {
|
|
3298
|
+
return this.content.add(obj, index);
|
|
3299
|
+
}
|
|
3300
|
+
remove(id) {
|
|
3301
|
+
this.content.remove(id);
|
|
3302
|
+
}
|
|
3303
|
+
getChildren() {
|
|
3304
|
+
return this.content.getChildren();
|
|
3305
|
+
}
|
|
3306
|
+
onMouseEvent(event) {
|
|
3307
|
+
if (event.type === "scroll") {
|
|
3308
|
+
let dir = event.scroll?.direction;
|
|
3309
|
+
if (event.modifiers.shift)
|
|
3310
|
+
dir = dir === "up" ? "left" : dir === "down" ? "right" : dir === "right" ? "down" : "up";
|
|
3311
|
+
if (dir === "up")
|
|
3312
|
+
this.scrollTop -= event.scroll?.delta ?? 0;
|
|
3313
|
+
else if (dir === "down")
|
|
3314
|
+
this.scrollTop += event.scroll?.delta ?? 0;
|
|
3315
|
+
else if (dir === "left")
|
|
3316
|
+
this.scrollLeft -= event.scroll?.delta ?? 0;
|
|
3317
|
+
else if (dir === "right")
|
|
3318
|
+
this.scrollLeft += event.scroll?.delta ?? 0;
|
|
3319
|
+
}
|
|
3320
|
+
if (event.type === "drag" && event.isSelecting) {
|
|
3321
|
+
this.updateAutoScroll(event.x, event.y);
|
|
3322
|
+
} else if (event.type === "up") {
|
|
3323
|
+
this.stopAutoScroll();
|
|
3324
|
+
}
|
|
3325
|
+
}
|
|
3326
|
+
handleKeyPress(key) {
|
|
3327
|
+
if (this.verticalScrollBar.handleKeyPress(key))
|
|
3328
|
+
return true;
|
|
3329
|
+
if (this.horizontalScrollBar.handleKeyPress(key))
|
|
3330
|
+
return true;
|
|
3331
|
+
return false;
|
|
3332
|
+
}
|
|
3333
|
+
startAutoScroll(mouseX, mouseY) {
|
|
3334
|
+
this.stopAutoScroll();
|
|
3335
|
+
this.autoScrollMouseX = mouseX;
|
|
3336
|
+
this.autoScrollMouseY = mouseY;
|
|
3337
|
+
this.cachedAutoScrollSpeed = this.getAutoScrollSpeed(mouseX, mouseY);
|
|
3338
|
+
this.isAutoScrolling = true;
|
|
3339
|
+
if (!this.live) {
|
|
3340
|
+
this.live = true;
|
|
3341
|
+
}
|
|
3342
|
+
}
|
|
3343
|
+
updateAutoScroll(mouseX, mouseY) {
|
|
3344
|
+
this.autoScrollMouseX = mouseX;
|
|
3345
|
+
this.autoScrollMouseY = mouseY;
|
|
3346
|
+
this.cachedAutoScrollSpeed = this.getAutoScrollSpeed(mouseX, mouseY);
|
|
3347
|
+
const scrollX = this.getAutoScrollDirectionX(mouseX);
|
|
3348
|
+
const scrollY = this.getAutoScrollDirectionY(mouseY);
|
|
3349
|
+
if (scrollX === 0 && scrollY === 0) {
|
|
3350
|
+
this.stopAutoScroll();
|
|
3351
|
+
} else if (!this.isAutoScrolling) {
|
|
3352
|
+
this.startAutoScroll(mouseX, mouseY);
|
|
3353
|
+
}
|
|
3354
|
+
}
|
|
3355
|
+
stopAutoScroll() {
|
|
3356
|
+
const wasAutoScrolling = this.isAutoScrolling;
|
|
3357
|
+
this.isAutoScrolling = false;
|
|
3358
|
+
this.autoScrollAccumulatorX = 0;
|
|
3359
|
+
this.autoScrollAccumulatorY = 0;
|
|
3360
|
+
if (wasAutoScrolling && !this.hasOtherLiveReasons()) {
|
|
3361
|
+
this.live = false;
|
|
3362
|
+
}
|
|
3363
|
+
}
|
|
3364
|
+
hasOtherLiveReasons() {
|
|
3365
|
+
return false;
|
|
3366
|
+
}
|
|
3367
|
+
handleAutoScroll(deltaTime) {
|
|
3368
|
+
if (!this.isAutoScrolling)
|
|
3369
|
+
return;
|
|
3370
|
+
const scrollX = this.getAutoScrollDirectionX(this.autoScrollMouseX);
|
|
3371
|
+
const scrollY = this.getAutoScrollDirectionY(this.autoScrollMouseY);
|
|
3372
|
+
const scrollAmount = this.cachedAutoScrollSpeed * (deltaTime / 1000);
|
|
3373
|
+
let scrolled = false;
|
|
3374
|
+
if (scrollX !== 0) {
|
|
3375
|
+
this.autoScrollAccumulatorX += scrollX * scrollAmount;
|
|
3376
|
+
const integerScrollX = Math.trunc(this.autoScrollAccumulatorX);
|
|
3377
|
+
if (integerScrollX !== 0) {
|
|
3378
|
+
this.scrollLeft += integerScrollX;
|
|
3379
|
+
this.autoScrollAccumulatorX -= integerScrollX;
|
|
3380
|
+
scrolled = true;
|
|
3381
|
+
}
|
|
3382
|
+
}
|
|
3383
|
+
if (scrollY !== 0) {
|
|
3384
|
+
this.autoScrollAccumulatorY += scrollY * scrollAmount;
|
|
3385
|
+
const integerScrollY = Math.trunc(this.autoScrollAccumulatorY);
|
|
3386
|
+
if (integerScrollY !== 0) {
|
|
3387
|
+
this.scrollTop += integerScrollY;
|
|
3388
|
+
this.autoScrollAccumulatorY -= integerScrollY;
|
|
3389
|
+
scrolled = true;
|
|
3390
|
+
}
|
|
3391
|
+
}
|
|
3392
|
+
if (scrolled) {
|
|
3393
|
+
this._ctx.requestSelectionUpdate();
|
|
3394
|
+
}
|
|
3395
|
+
if (scrollX === 0 && scrollY === 0) {
|
|
3396
|
+
this.stopAutoScroll();
|
|
3397
|
+
}
|
|
3398
|
+
}
|
|
3399
|
+
getAutoScrollDirectionX(mouseX) {
|
|
3400
|
+
const relativeX = mouseX - this.x;
|
|
3401
|
+
const distToLeft = relativeX;
|
|
3402
|
+
const distToRight = this.width - relativeX;
|
|
3403
|
+
if (distToLeft <= this.autoScrollThresholdHorizontal) {
|
|
3404
|
+
return this.scrollLeft > 0 ? -1 : 0;
|
|
3405
|
+
} else if (distToRight <= this.autoScrollThresholdHorizontal) {
|
|
3406
|
+
const maxScrollLeft = this.scrollWidth - this.viewport.width;
|
|
3407
|
+
return this.scrollLeft < maxScrollLeft ? 1 : 0;
|
|
3408
|
+
}
|
|
3409
|
+
return 0;
|
|
3410
|
+
}
|
|
3411
|
+
getAutoScrollDirectionY(mouseY) {
|
|
3412
|
+
const relativeY = mouseY - this.y;
|
|
3413
|
+
const distToTop = relativeY;
|
|
3414
|
+
const distToBottom = this.height - relativeY;
|
|
3415
|
+
if (distToTop <= this.autoScrollThresholdVertical) {
|
|
3416
|
+
return this.scrollTop > 0 ? -1 : 0;
|
|
3417
|
+
} else if (distToBottom <= this.autoScrollThresholdVertical) {
|
|
3418
|
+
const maxScrollTop = this.scrollHeight - this.viewport.height;
|
|
3419
|
+
return this.scrollTop < maxScrollTop ? 1 : 0;
|
|
3420
|
+
}
|
|
3421
|
+
return 0;
|
|
3422
|
+
}
|
|
3423
|
+
getAutoScrollSpeed(mouseX, mouseY) {
|
|
3424
|
+
const relativeX = mouseX - this.x;
|
|
3425
|
+
const relativeY = mouseY - this.y;
|
|
3426
|
+
const distToLeft = relativeX;
|
|
3427
|
+
const distToRight = this.width - relativeX;
|
|
3428
|
+
const distToTop = relativeY;
|
|
3429
|
+
const distToBottom = this.height - relativeY;
|
|
3430
|
+
const minDistance = Math.min(distToLeft, distToRight, distToTop, distToBottom);
|
|
3431
|
+
if (minDistance <= 1) {
|
|
3432
|
+
return this.autoScrollSpeedFast;
|
|
3433
|
+
} else if (minDistance <= 2) {
|
|
3434
|
+
return this.autoScrollSpeedMedium;
|
|
3435
|
+
} else {
|
|
3436
|
+
return this.autoScrollSpeedSlow;
|
|
3437
|
+
}
|
|
3438
|
+
}
|
|
3439
|
+
recalculateBarProps() {
|
|
3440
|
+
this.verticalScrollBar.scrollSize = this.content.height;
|
|
3441
|
+
this.verticalScrollBar.viewportSize = this.viewport.height;
|
|
3442
|
+
this.horizontalScrollBar.scrollSize = this.content.width;
|
|
3443
|
+
this.horizontalScrollBar.viewportSize = this.viewport.width;
|
|
3444
|
+
}
|
|
3445
|
+
set rootOptions(options) {
|
|
3446
|
+
Object.assign(this, options);
|
|
3447
|
+
this.requestRender();
|
|
3448
|
+
}
|
|
3449
|
+
set wrapperOptions(options) {
|
|
3450
|
+
Object.assign(this.wrapper, options);
|
|
3451
|
+
this.requestRender();
|
|
3452
|
+
}
|
|
3453
|
+
set viewportOptions(options) {
|
|
3454
|
+
Object.assign(this.viewport, options);
|
|
3455
|
+
this.requestRender();
|
|
3456
|
+
}
|
|
3457
|
+
set contentOptions(options) {
|
|
3458
|
+
Object.assign(this.content, options);
|
|
3459
|
+
this.requestRender();
|
|
3460
|
+
}
|
|
3461
|
+
set scrollbarOptions(options) {
|
|
3462
|
+
Object.assign(this.verticalScrollBar, options);
|
|
3463
|
+
Object.assign(this.horizontalScrollBar, options);
|
|
3464
|
+
this.requestRender();
|
|
3465
|
+
}
|
|
3466
|
+
set verticalScrollbarOptions(options) {
|
|
3467
|
+
Object.assign(this.verticalScrollBar, options);
|
|
3468
|
+
this.requestRender();
|
|
3469
|
+
}
|
|
3470
|
+
set horizontalScrollbarOptions(options) {
|
|
3471
|
+
Object.assign(this.horizontalScrollBar, options);
|
|
3472
|
+
this.requestRender();
|
|
3473
|
+
}
|
|
3474
|
+
destroySelf() {
|
|
3475
|
+
if (this.selectionListener) {
|
|
3476
|
+
this._ctx.off("selection", this.selectionListener);
|
|
3477
|
+
this.selectionListener = undefined;
|
|
3478
|
+
}
|
|
3479
|
+
super.destroySelf();
|
|
3480
|
+
}
|
|
3481
|
+
}
|
|
2677
3482
|
// src/renderables/composition/constructs.ts
|
|
2678
3483
|
function Generic(props, ...children) {
|
|
2679
3484
|
return h(VRenderable, props || {}, ...children);
|
|
@@ -2751,6 +3556,7 @@ export {
|
|
|
2751
3556
|
isValidPercentage,
|
|
2752
3557
|
isVNode,
|
|
2753
3558
|
isSizeType,
|
|
3559
|
+
isRenderable,
|
|
2754
3560
|
isPositionTypeType,
|
|
2755
3561
|
isPositionType,
|
|
2756
3562
|
isPaddingType,
|
|
@@ -2780,6 +3586,7 @@ export {
|
|
|
2780
3586
|
createTextAttributes,
|
|
2781
3587
|
createCliRenderer,
|
|
2782
3588
|
coordinateToCharacterIndex,
|
|
3589
|
+
convertGlobalToLocalSelection,
|
|
2783
3590
|
capture,
|
|
2784
3591
|
brightYellow,
|
|
2785
3592
|
brightWhite,
|
|
@@ -2814,7 +3621,6 @@ export {
|
|
|
2814
3621
|
VRenderable,
|
|
2815
3622
|
TrackedNode,
|
|
2816
3623
|
Timeline,
|
|
2817
|
-
TextSelectionHelper,
|
|
2818
3624
|
TextRenderable,
|
|
2819
3625
|
TextBuffer,
|
|
2820
3626
|
TextAttributes,
|
|
@@ -2829,6 +3635,8 @@ export {
|
|
|
2829
3635
|
SelectRenderableEvents,
|
|
2830
3636
|
SelectRenderable,
|
|
2831
3637
|
Select,
|
|
3638
|
+
ScrollBoxRenderable,
|
|
3639
|
+
ScrollBarRenderable,
|
|
2832
3640
|
RootRenderable,
|
|
2833
3641
|
RenderableEvents,
|
|
2834
3642
|
Renderable,
|
|
@@ -2858,10 +3666,11 @@ export {
|
|
|
2858
3666
|
BorderCharArrays,
|
|
2859
3667
|
BlurEffect,
|
|
2860
3668
|
BloomEffect,
|
|
3669
|
+
ArrowRenderable,
|
|
2861
3670
|
ASCIIFontSelectionHelper,
|
|
2862
3671
|
ASCIIFontRenderable,
|
|
2863
3672
|
ASCIIFont
|
|
2864
3673
|
};
|
|
2865
3674
|
|
|
2866
|
-
//# debugId=
|
|
3675
|
+
//# debugId=B627209D76BECE1A64756E2164756E21
|
|
2867
3676
|
//# sourceMappingURL=index.js.map
|