diff --git a/core/scope.js b/core/scope.js index bb38f4b13ba1f0808a8326b6b1df8ce3756f05e5..8f20ddc5d2e327aab1275e0c4805b5799dceb153 100644 --- a/core/scope.js +++ b/core/scope.js @@ -289,14 +289,101 @@ export default function Scope(wrapper, tlv) { } } + let open = (context) => { + // new plane every time! + context.plane = $('<div>').addClass('subplane').addClass('block').attr('id', `${def.name}_plane`).get(0) + context.plane.position = () => { + return { x: 0, y: blocks.getBlockStackHeight(def.blocks) } + } + if (!context.size) context.size = { x: 800, y: 600 } + dt.writeContainerSize(context.size) + // blocks should have handles, + context.plane.handle = context // this is a throwaway ... and maybe ah bugfarm + // the context should be .within an ldef, we want this block to carry the plane around, + let ldef = context.within + ldef.blocks.push(context.plane) + ldef.blocks[0].take(context.plane) // 'parent' block, for positioning, kind of awkward + // existence + $(ldef.context.plane).append(context.plane) + // handle resize, + dt.addResizeHandle(context.plane) + context.plane.onresize = (deltas) => { + let size = dt.readContainerSize(context.plane) + size.x += deltas.x + size.y += deltas.y + dt.writeContainerSize(context.plane, size) + repositionDef(def) + // reposition all defs in the downstream: we might be squishing them about: + for (let dsdef of context.defs) { + repositionDef(dsdef) + } + } // end onresize, + // place, + repositionDef(def) + // toggle button state, + $(squid).html('<i class="em em-shell"></i> collapse link') + $(squid).one('click', close) + /* + if (def.states[0].value) { // if is-connecting, + context.refresh().then(() => { + // ? + }).catch((err) => { + console.error(err) + }) + } + */ + } + + + let close = (context) => { + console.error('nah') + /* + // 'ldef.contains' is a ptr to the context (view) that is w i t h i n the link, accoring + // to our earlier piping, ldef.contains = view returned here + wipeContext(ldef.contains) + $(ldef.contains.plane).remove() + // arduous: rm from ldef, and from titleblock, + let bi = ldef.blocks.findIndex((cand) => { + return (cand === ldef.contains.plane) + }) + if (bi >= 0) { + ldef.blocks.splice(bi, 1) + } else { + console.error('lost plane block ... ') + } + titleblock.remove(ldef.contains.plane) + delete ldef.contains.plane + // . then-> + + $(squid).html('<i class="em em-squid"></i> expand link') + $(squid).one('click', open) + repositionDef(ldef) + */ + } + this.check = () => { // check levels recursively, - let recursor = (view) => { - checkView(view) - for (let def of view.defs) { - if (def.contains) { - if (!def.contains.plane) continue - recursor(def.contains) + let recursor = (context) => { + checkView(context) + for (let def of context.defs) { + if (def.type == 'link') { + // find the context it's connected to, + def.context.getLinkContext(def).then((nc) => { // next context, + if (nc.open && !nc.plane) { // open, no plane, so we build one: + console.log('opening') + console.log(nc.plane) // nc / linkcontext maybe not what you think it is ? + here you are + open(nc) + } + if (nc.plane && !nc.open) { // exist, but should be closed, run that + close(nc) + } + if (nc.plane) { // if plane still up, we passed the last if, recurse down + recursor(nc) + } + }).catch(() => { + // noop, no context, + }) } } } diff --git a/hunks/view.js b/hunks/view.js index 4357872e8d2e6a73c5969321e6b672b332d64c0a..3b3e12cf09cb3abf695fd708273216f227ac4eb7 100644 --- a/hunks/view.js +++ b/hunks/view.js @@ -42,6 +42,21 @@ function View() { let defs = new Array this.defs = defs + // some global state for the remote interpreter: + this.interpreterName = null + this.interpreterVersion = null + + /* + views have some persistent state, and we link them to one another, so this is nice to know, + views have this shape: { + defs: [<ptrs to defs>], // objects, see below + interpreterName: <string>, // name of df world we are talking to, + interpreterVersion: <string>, // of the same, + within: <ptr to link-def>, // if exists, we are nested inside of this link + size: {w: <number>, h: <number>}, // if exists, render this. size to render at. + } + */ + /* the view maintains this list of definitions to match state of remote dataflow environments defs have this shape: { @@ -49,6 +64,10 @@ function View() { name: <string>, // the name of the thing, ind: <number>, // own index of the def, in this array (and the managers), context: <ptr to view>, // so def.context.defs[def.ind] is circular, + // LINK-specific: + contains: <ptr to view>, // ~ potentially ~ exists, if this is a link piped to a view (per upper level connectivity!) + downstream: <ptr to link>, // ~ potentially ~ exists, meaning this bridges to that link, and that link is 'down' one level + upstream: <ptr to link>, // ~ potentially ~ exists, meaning that this link bridge to that link, that link is 'up' one level inputs: [ // a list of inputs, each of which: { type: <string>, // the type, types are strings 4 js @@ -95,10 +114,6 @@ function View() { /* -------------------- RENDER INTERFACE --------------------- */ /* --------------------------- ---------------------------- */ - // some global state for the remote interpreter: - this.interpreterName = null - this.interpreterVersion = null - // we interface to the UI by setting these flags... // when we make big changes, just nuke 'em // mostly, this is useful for any deleted hunks, or the refresh @@ -305,7 +320,9 @@ function View() { // rm everything ... for (let key in def) { if (def.hasOwnProperty(key)) { - if (key == 'type' || key == 'name' || key == 'ind' || key == 'context' || key == 'inputs' || key == 'outputs' || key == 'states') { + if (key == 'type' || key == 'name' || key == 'ind' || + key == 'context' || key == 'inputs' || key == 'outputs' || key == 'states' || + key == 'contains' || key == 'downstream' || key == 'upstream') { // these we keep, } else { delete def[key] @@ -731,6 +748,17 @@ function View() { // with recepies, we take the atomic units above and do larger order operations // wipes current state from remote, polls from zero + /* + so, at the moment the replaceDef that occurs when we go to build a route + manages to wipe some of the state out of the route - probably we are + cleaning defs in our view, that is erasing graph knowledge. this means + we should probably prune the cleanup, and try to make some careful sense of what's going on + when we run the redrawing op as well ... + ... yeah, recall that expanding / contracting w/e is stateful at the button. this is indeed + a new days' can of worms + ... perhaps the way to do this is to set a global .norefresh flag, see if the route building alone works + and then handle etcs afterwards, i.e. probably just cleaning up .clean() (ha) + */ this.refresh = () => { console.log('REFRESH') // well, I won't say it's clean or beautiful, but we are interested in keeping the @@ -1064,36 +1092,41 @@ function View() { } } + this.makeLinkContext = (ldef) => { + return new Promise((resolve, reject) => { + this.getLinkContext(ldef).then((context) => { + resolve(context) + }).catch(async () => { + // none, make one, + try { + let vdef = await window.tlv.requestAddHunk('view') + await this.buildRoute(vdef.outputs[0], ldef.inputs[1]) + await this.buildRoute(ldef.outputs[1], vdef.inputs[0]) + let view = vdef.hunk // views are always toplevel hunks, so they always have these handles + resolve(view) + } catch (err) { + console.error(err) + reject() + } + }) + }) + } + // for any link, find / build a route up to a view, from its' 1st input / output - that are assumed to be manager // message ports to the manager within that link... this.getLinkContext = (ldef) => { - // oof async so nice - return new Promise(async (resolve, reject) => { - // ok, - let view + return new Promise((resolve, reject) => { let tr = this.trace(ldef.outputs[1]) if (tr) { if (tr.parent.type == 'view') { - // keep our ptrs together - view = tr.parent.hunk + tr.parent.hunk.within = ldef + ldef.contains = tr.parent.hunk + resolve(tr.parent.hunk) } else { - console.error('need to write case for this, likely that we are link->link here') - reject('no link traversing trace yet, pls write') + reject('looking for context, traces to non-view... ') } } else { - try { - let vdef = await window.tlv.requestAddHunk('view') - await this.requestAddLink(vdef.outputs[0], ldef.inputs[1]) - await this.requestAddLink(ldef.inputs[1], vdef.outputs[0]) - view = vdef.hunk // views are always toplevel hunks, so they always have these handles - } catch (err) { - reject(err) - } - } - if (view) { - view.within = ldef - ldef.contains = view - resolve(view) + reject() } }) } @@ -1196,8 +1229,8 @@ function View() { let porthole = route[route.length - 1].exit let portlist = porthole.states[3].value portlist += `, at_${porthole.outputs.length} (${type})` - await ipdef.context.requestStateChange(porthole.states[3], portlist) - await ipdef.context.requestAddLink(porthole.outputs[porthole.outputs.length - 1], ipdef) + await ipdef.parent.context.requestStateChange(porthole.states[3], portlist) + await ipdef.parent.context.requestAddLink(porthole.outputs[porthole.outputs.length - 1], ipdef) // to avoid piping data into the void, we can do this last -> await gateway.context.requestAddLink(opdef, gateway.inputs[gateway.inputs.length - 1]) resolve() diff --git a/style.css b/style.css index 13671b999293646834a980d3540b21437c415afa..fd42f433b651f61733596b640a0aba7c21e374ad 100644 --- a/style.css +++ b/style.css @@ -127,6 +127,7 @@ body { /* is title and state */ .defcore { width: 275px; + height: 20px; font-size: 15px; font-weight: bold; font-style: italic; @@ -149,19 +150,10 @@ body { position: absolute; } -.inputs { - position:absolute; - width: 117px; - float: left; - margin-left: 2px; - font-size: 11px; - background-color: #1a1a1a; - color: #eee; -} - .input { position:absolute; width: 100px; + height: 20px; text-align: left; font-size: 11px; background-color: #1a1a1a; @@ -177,20 +169,10 @@ body { padding: 2px; } -.outputs { - position: absolute; - width: 117px; - float: right; - margin-right: 2px; - text-align: right; - font-size: 11px; - background-color: #1a1a1a; - color: #eee; -} - .output { position: absolute; width: 100px; + height: 20px; text-align: right; font-size: 11px; background-color: #1a1a1a; diff --git a/view/blocks.js b/view/blocks.js index 98a9e77a6bf7bc44705d6c51a5dd46257c92e256..7f8556cdcd8beb5c14375195956f2e0c20dda133 100644 --- a/view/blocks.js +++ b/view/blocks.js @@ -84,63 +84,12 @@ let makeLink = (ldef, titleblock) => { titleblock.take(squid) ldef.blocks.push(squid) let open = (evt) => { - // returns the view that connects to this link, - ldef.context.getLinkContext(ldef).then((view) => { - // oh lawd - view.plane = $('<div>').addClass('subplane').addClass('block').attr('id', `${ldef.name}_plane`).get(0) - view.plane.position = () => { - return { x: 0, y: getBlockStackHeight(ldef.blocks) } - } - view.plane.handle = view // this is a throwaway ... and maybe ah bugfarm - ldef.blocks.push(view.plane) - titleblock.take(view.plane) - $(window.tlv.plane).append(view.plane) - dt.addResizeHandle(view.plane) - view.plane.onresize = (deltas) => { - let size = dt.readContainerSize(view.plane) - size.x += deltas.x - size.y += deltas.y - dt.writeContainerSize(view.plane, size) - repositionDef(ldef) - // reposition all defs in the downstream: we might be squishing them about: - for(let dsdef of ldef.downstream.context.defs){ - repositionDef(dsdef) - } - } - // and, - repositionDef(ldef) - // toggle button state, - $(squid).html('<i class="em em-shell"></i> collapse link') - $(squid).one('click', close) - view.refresh().then(() => { - // ? - }).catch((err) => { - console.error(err) - }) - }).catch((err) => { - console.error(err) + ldef.context.makeLinkContext(ldef).then((context) => { + context.open = true }) } let close = (evt) => { - // 'ldef.contains' is a ptr to the context (view) that is w i t h i n the link, accoring - // to our earlier piping, ldef.contains = view returned here - wipeContext(ldef.contains) - $(ldef.contains.plane).remove() - // arduous: rm from ldef, and from titleblock, - let bi = ldef.blocks.findIndex((cand) => { - return (cand === ldef.contains.plane) - }) - if (bi >= 0) { - ldef.blocks.splice(bi, 1) - } else { - console.error('lost plane block ... ') - } - titleblock.remove(ldef.contains.plane) - delete ldef.contains.plane - // . then-> - $(squid).html('<i class="em em-squid"></i> expand link') - $(squid).one('click', open) - repositionDef(ldef) + ldef.contains.open = false } $(squid).html('<i class="em em-squid"></i> expand link') $(squid).one('click', open) @@ -148,8 +97,8 @@ let makeLink = (ldef, titleblock) => { // static title, titleblock.position = () => { let y = 0; - for(let ipd of ldef.inputs){ - y += ipd.block.clientHeight + 5 + for(let opd of ldef.outputs){ + y += opd.block.clientHeight + 5 } return { x: 0, y: y } } @@ -353,10 +302,12 @@ let rebuildDef = (def, position) => { inputblock.position = () => { // is this hella dollars? if (def.contains && def.contains.plane) { + // draw wrap-around, // I wonder if this is going to bog us down, // ideally redrawing would be list-based, with longer trees of offsetparents ... return { x: -inputblock.clientWidth - 5, y: getBlockStackHeight(def.blocks) + (inputblock.clientHeight + 5) * i } } else if (def.upstream) { + // draw wrap-within, // we have an upstream link, i.e. we are the unwrapped thing, // inputs go right, return {