code wiki / _hdl_build / nx_editor_canvas.nx

nx_editor_canvas.nx source

↩ module page · 102 lines · 5191 B

1// nx_editor_canvas.nx -- the EDITOR engine: the sovereign, gateable CORE of a visual editor, as data+logic so it can 2// be PROVEN without a browser. A canvas is a flat i64 array of N elements, 5 fields each: [kind, x, y, w, h]. 3// Operations: snap-all-to-grid, align (L/R/T/B/center-h/middle-v), distribute-horizontally (even left edges), nudge, 4// and one-deep undo (snapshot/restore). The surface is rendered NO-JS (ec_render); editing = server ops (apply an op, 5// re-render), never a client-side JS canvas -- a JS drag-drop canvas is the JS-heavy approach the Nishi ecosystem 6// REJECTS, not a maturity bar to chase. SOVEREIGN + no-JS + governed. REUSE: nx_brand_snap (bs_snap). 7// license_tier: ORIGINAL 8import "nx_syscalls.nx" 9import "nx_brand_snap.nx" 10 11const EC_STRIDE: i64 = 5 // [kind, x, y, w, h] 12 13// snap every element's x/y/w onto the grid. 14func ec_snap_all(c: *i64, n: i64, grid: i64) -> i64 { 15 var i: i64 = 0 16 while i < n { 17 c[i*EC_STRIDE + 1] = bs_snap(c[i*EC_STRIDE + 1], grid) 18 c[i*EC_STRIDE + 2] = bs_snap(c[i*EC_STRIDE + 2], grid) 19 c[i*EC_STRIDE + 3] = bs_snap(c[i*EC_STRIDE + 3], grid) 20 i = i + 1 21 } 22 return 0 23} 24// align all elements: mode 0=left 1=right 2=top 3=bottom 4=center-h 5=middle-v (to the bounding box). 25func ec_align(c: *i64, n: i64, mode: i64) -> i64 { 26 if n < 1 { return 0 } 27 var minx: i64 = c[1]; var maxr: i64 = c[1] + c[3] 28 var miny: i64 = c[2]; var maxb: i64 = c[2] + c[4] 29 var i: i64 = 1 30 while i < n { 31 let x: i64 = c[i*EC_STRIDE+1]; let r: i64 = x + c[i*EC_STRIDE+3] 32 let y: i64 = c[i*EC_STRIDE+2]; let b: i64 = y + c[i*EC_STRIDE+4] 33 if x < minx { minx = x } 34 if r > maxr { maxr = r } 35 if y < miny { miny = y } 36 if b > maxb { maxb = b } 37 i = i + 1 38 } 39 i = 0 40 while i < n { 41 if mode == 0 { c[i*EC_STRIDE+1] = minx } 42 if mode == 1 { c[i*EC_STRIDE+1] = maxr - c[i*EC_STRIDE+3] } 43 if mode == 2 { c[i*EC_STRIDE+2] = miny } 44 if mode == 3 { c[i*EC_STRIDE+2] = maxb - c[i*EC_STRIDE+4] } 45 if mode == 4 { c[i*EC_STRIDE+1] = (minx + maxr)/2 - c[i*EC_STRIDE+3]/2 } 46 if mode == 5 { c[i*EC_STRIDE+2] = (miny + maxb)/2 - c[i*EC_STRIDE+4]/2 } 47 i = i + 1 48 } 49 return 0 50} 51// distribute left edges evenly between the leftmost and rightmost element (elements given in visual x-order). 52func ec_distribute_h(c: *i64, n: i64) -> i64 { 53 if n < 2 { return 0 } 54 var minx: i64 = c[1]; var maxx: i64 = c[1] 55 var i: i64 = 1 56 while i < n { let x: i64 = c[i*EC_STRIDE+1]; if x < minx { minx = x } if x > maxx { maxx = x } i = i + 1 } 57 let span: i64 = maxx - minx 58 i = 0 59 while i < n { c[i*EC_STRIDE+1] = minx + (i*span)/(n-1); i = i + 1 } 60 return 0 61} 62// move one element. 63func ec_nudge(c: *i64, idx: i64, dx: i64, dy: i64) -> i64 { 64 c[idx*EC_STRIDE+1] = c[idx*EC_STRIDE+1] + dx 65 c[idx*EC_STRIDE+2] = c[idx*EC_STRIDE+2] + dy 66 return 0 67} 68// snapshot / restore (one-deep undo; a history stack is the follow-on). 69func ec_save(c: *i64, n: i64, hist: *i64) -> i64 { var i: i64 = 0; while i < n*EC_STRIDE { hist[i] = c[i]; i = i + 1 } return 0 } 70func ec_undo(c: *i64, n: i64, hist: *i64) -> i64 { var i: i64 = 0; while i < n*EC_STRIDE { c[i] = hist[i]; i = i + 1 } return 0 } 71 72// ---- NO-JS render: the canvas as absolutely-positioned HTML via CSS only (ZERO JavaScript) ---- 73// The sovereign editor's surface is server-rendered + CSS-positioned -- editing is server ops (apply an engine op, 74// re-render), never a client-side JS canvas. This is the no-JS-unless-mandatory doctrine made literal. 75func ec_w(fd: i64, s: *u8) -> i64 { var n: i64=0; while s[n]!=(0 as u8){n=n+1} sys_write(fd,s,n); return 0 } 76func ec_wn(fd: i64, v: i64) -> i64 { 77 if v == 0 { sys_write(fd, "0" as *u8, 1); return 0 } 78 var m: i64 = v; if m < 0 { sys_write(fd, "-" as *u8, 1); m = 0 - m } 79 let d: *u8 = sys_mmap(24); var k: i64 = 0 80 while m > 0 { d[k] = (48 + (m % 10)) as u8; m = m / 10; k = k + 1 } 81 var i: i64 = k - 1 82 while i >= 0 { let o: *u8 = sys_mmap(1); o[0] = d[i]; sys_write(fd, o, 1); i = i - 1 } 83 return 0 84} 85func ec_kindlabel(k: i64) -> *u8 { if k==1 { return "heading" as *u8 } if k==2 { return "text" as *u8 } if k==3 { return "button" as *u8 } if k==4 { return "image" as *u8 } return "block" as *u8 } 86// render the canvas to an fd as absolutely-positioned divs (CSS only, NO JavaScript). Token-driven borders. 87func ec_render(c: *i64, n: i64, fd: i64) -> i64 { 88 ec_w(fd, "<div class=\"nx-canvas\" style=\"position:relative;min-height:480px;border:1px solid var(--nx-color-line)\">\n" as *u8) 89 var i: i64 = 0 90 while i < n { 91 ec_w(fd, "<div class=\"nx-el\" style=\"position:absolute;left:" as *u8) 92 ec_wn(fd, c[i*EC_STRIDE+1]); ec_w(fd, "px;top:" as *u8); ec_wn(fd, c[i*EC_STRIDE+2]) 93 ec_w(fd, "px;width:" as *u8); ec_wn(fd, c[i*EC_STRIDE+3]); ec_w(fd, "px;height:" as *u8); ec_wn(fd, c[i*EC_STRIDE+4]) 94 ec_w(fd, "px;border:1px solid var(--nx-color-line);padding:4px\">" as *u8) 95 ec_w(fd, ec_kindlabel(c[i*EC_STRIDE+0])) 96 ec_w(fd, "</div>\n" as *u8) 97 i = i + 1 98 } 99 ec_w(fd, "</div>\n" as *u8) 100 return 0 101} 102