summaryrefslogtreecommitdiff
path: root/src/web/app.mjs
diff options
context:
space:
mode:
Diffstat (limited to 'src/web/app.mjs')
-rw-r--r--src/web/app.mjs37
1 files changed, 33 insertions, 4 deletions
diff --git a/src/web/app.mjs b/src/web/app.mjs
index 2a4f8a65..3dcf6ab5 100644
--- a/src/web/app.mjs
+++ b/src/web/app.mjs
@@ -55,10 +55,16 @@ export class DomRenderer {
const cursorBar = this.wasm.pardes_cursor_bar() !== 0;
const raw = new Array(count);
const tagCovered = new Uint8Array(count);
+ const tagGrips = new Map();
if (this.wasm.pardes_tag_layer_limit) {
for (let i = 0; i < this.wasm.pardes_tag_layer_limit(); i++) {
const val = field => this.wasm.pardes_tag_layer_value(i, field);
if (!val(0)) continue;
+ const gripCols = this.wasm.pardes_grip_columns?.() ?? 2;
+ if (val(1) !== 0 && val(4) >= gripCols && this.cellHeight) {
+ const offset = this.wasm.pardes_tagline_band_offset(val(5),rows*this.cellHeight*256,Math.round(this.cellHeight*256),Math.round(this.taglineHeight*256))/256;
+ for (let x = val(4)-gripCols; x < val(4); x++) tagGrips.set(val(5)*cols+x,offset);
+ }
for (let x = val(4); x < Math.min(cols, val(4) + val(6)); x++) {
if (val(5) < rows) tagCovered[val(5) * cols + x] = 1;
}
@@ -77,6 +83,10 @@ export class DomRenderer {
const cursor = x === cursorX && y === cursorY;
const cell = this.cells[index];
cell.style.visibility = tagCovered[index] ? "hidden" : "";
+ const gripOffset = tagGrips.get(index);
+ cell.style.height = gripOffset === undefined ? "" : `${this.taglineHeight}px`;
+ cell.style.lineHeight = gripOffset === undefined ? "" : `${this.taglineHeight}px`;
+ cell.style.marginTop = gripOffset === undefined ? "" : `${gripOffset}px`;
if (cell.textContent !== text) cell.textContent = text;
const styleKey = `${fg}:${bg}:${attrs}:${cursor ? 1 : 0}:${cursorBar ? 1 : 0}`;
if (cell.pardesStyle !== styleKey) {
@@ -86,12 +96,12 @@ export class DomRenderer {
raw[index] = { text, fg, bg, attrs };
}
this.renderBodyLayers();
- this.renderTagLayers();
+ this.renderTagLayers(raw);
this.snapshot = { cols, rows, cells: raw, cursorX, cursorY, cursorBar };
return this.snapshot;
}
- renderTagLayers() {
+ renderTagLayers(canonical) {
if (!this.wasm.pardes_tag_layer_limit || !this.cellWidth) return;
if (!this.tagRoot?.isConnected) {
this.tagRoot = this.root.ownerDocument.createElement("div");
@@ -110,10 +120,15 @@ export class DomRenderer {
if (!ptr) continue;
const bytes = new Uint8Array(this.wasm.memory.buffer,ptr,cols*CELL_SIZE);
const offset = this.wasm.pardes_tagline_band_offset(values[5],this.rowCount*bh*256,Math.round(bh*256),Math.round(th*256))/256;
- const geometry = [bw,bh,tw,th,offset,...values].join(":");
+ const gripCols = this.wasm.pardes_grip_columns?.() ?? 2;
+ const gripX = values[4] - gripCols;
+ const gripCell = canonical[values[5]*this.cols+gripX];
+ const grip = values[1] !== 0 && gripX >= 0 && gripCell?.text === " " && th >= 6 && tw >= 3;
+ const geometry = [bw,bh,tw,th,offset,...values,grip,gripCell?.fg].join(":");
const cached = this.tagNodes.get(i);
if (cached && cached.geometry === geometry && cached.bytes.length === bytes.length && cached.bytes.every((byte,index)=>byte===bytes[index])) {
nodes.push(cached.node);
+ if (cached.grip) nodes.push(cached.grip);
continue;
}
const view = new DataView(this.wasm.memory.buffer,ptr,cols*CELL_SIZE);
@@ -132,8 +147,22 @@ export class DomRenderer {
cell.style.lineHeight = `${th}px`;
layer.append(cell);
}
- this.tagNodes.set(i,{geometry,bytes:bytes.slice(),node:layer});
+ let gripNode = null;
+ if (grip) {
+ gripNode = this.root.ownerDocument.createElement("div");
+ gripNode.dataset.tagGrip = String(i);
+ const centerX = (gripX+gripCols/2)*bw, centerY = values[5]*bh+offset+th/2;
+ const half = Math.max(1,Math.min(3,bw-2));
+ gripNode.style.cssText = "position:absolute;inset:0;pointer-events:none";
+ for (const dy of [-2,1]) {
+ const mark = this.root.ownerDocument.createElement("div");
+ mark.style.cssText = `position:absolute;left:${Math.floor(centerX-half)}px;top:${Math.floor(centerY+dy)}px;width:${2*half}px;height:1px;background:${color(gripCell.fg,DEFAULT_FG)}`;
+ gripNode.append(mark);
+ }
+ }
+ this.tagNodes.set(i,{geometry,bytes:bytes.slice(),node:layer,grip:gripNode});
nodes.push(layer);
+ if (gripNode) nodes.push(gripNode);
}
if (nodes.length !== this.tagRoot.childNodes.length || nodes.some((node,index)=>node!==this.tagRoot.childNodes[index])) this.tagRoot.replaceChildren(...nodes);
}