From c61d0d4475e9639814795b4eec2adc2d15fc9d83 Mon Sep 17 00:00:00 2001 From: Jake <jake.read@cba.mit.edu> Date: Thu, 2 May 2019 16:59:10 -0400 Subject: [PATCH] program save! --- README.md | 11 +++- hunks/interface/number.js | 9 +-- hunks/view.js | 118 ++++++++++++++++++++++++++--------- style.css | 28 +++++++++ typeset.js | 28 ++++++++- view/vdom.js | 4 +- view/vptch.js | 127 ++++++++++++++++++++++++++++++++++++++ 7 files changed, 288 insertions(+), 37 deletions(-) create mode 100644 view/vptch.js diff --git a/README.md b/README.md index 60f97bf..f4e98b0 100644 --- a/README.md +++ b/README.md @@ -14,6 +14,15 @@ Native Cuttlefish 'Hunks' are given access to a DOM/div element, making them nic # Scratch +'aye, but as the legends state: software doth make the hardware singeth' + + -> typeset + - do name -> names: ['float64', 'number'], for same byte-cast for colloquial type cast ... i.e. uint8 and byte, ? what else ? is it worth it, or just copy pasta ? should also be lists of things that can be hooked up ! + + -> with programs, prototype a bootstrap that loads cuttlefish and waits ... then loads a program there ? + +maybe this is something of a JAMTOC moment ... the view stores and manipulates represenations, we only need a minimum set of messages to load that representation remotely + I'm very close, though, and want to focus. I should be talking to a nautilus manager tonight and prototyping how I want remote resources to open up from cuttlefish. OK. I'm just through serializing things. I'd really like to be into ponyo early tomorrow. @@ -30,7 +39,7 @@ questions - why does a new view init with the same 'ok' in the titlebox / msgbox ? - because #ids are not really unique and you were jquerying to the (0th) instance -... +... then, go to nautilus, write cobserial, consider how to quickload program for ponyo test The next meaningful work on ponyo happens when I can: diff --git a/hunks/interface/number.js b/hunks/interface/number.js index 15f38d2..a531fda 100644 --- a/hunks/interface/number.js +++ b/hunks/interface/number.js @@ -14,14 +14,15 @@ import { function Number() { Hunkify(this, 'Number Input') - let numout = new Output('Number', 'num') + let numout = new Output('number', 'num') this.outputs.push(numout) + let numrep = new State('number', 'numrep', 275074) + this.state.push(numrep) + // as is tradition, this.dom = {} - let num = 250112 - this.init = () => { // manager calls this once // it is loaded and state is updated (from program) @@ -30,7 +31,7 @@ function Number() { let contact = $('<div>').addClass('btn').append('! contact !').get(0) $(this.dom).append(contact) contact.addEventListener('click', (evt) => { - numout.put(num += 1) + numout.put(numrep.value) }) } diff --git a/hunks/view.js b/hunks/view.js index e6944ea..7789920 100644 --- a/hunks/view.js +++ b/hunks/view.js @@ -30,6 +30,7 @@ import { import DomTools from '../view/vdom.js' import BezierTools from '../view/vbzt.js' import MessageBox from '../view/vmsg.js' +import PatchSet from '../view/vptch.js' function View() { Hunkify(this, 'View') @@ -55,6 +56,8 @@ function View() { let msgbox = new MessageBox(this) // and tools for the links, let bzt = new BezierTools(this) + // and for program (patch) management + let patchset = new PatchSet(this, msgbox) /* --------------------------- ---------------------------- */ /* -------------------- INIT, LISTENERS ---------------------- */ @@ -69,6 +72,8 @@ function View() { this.plane = $('<div>').addClass('plane').get(0) // to log, type, etc msgbox.init() + // for programs + //patchset.init() // init transform of the plane, let dft = { s: 1, @@ -203,44 +208,91 @@ function View() { -> save this program -> reload this view -> heartbeat checkin - */ - - // TRANSFORM here to write menu in the right spot on click - let menu = $('<div>').addClass('contextmenu') - .append('<ul>requesting available hunks ... </ul>').get(0) + console.log('context...', evt) + // make the menu, + let menu = $('<div>').addClass('contextmenu').get(0) + // and place, let pt = dt.readTransform(this.plane) - console.log(pt) - ///console.log('write to ', ct) + console.log('plane transform', pt) + // HERE: there's still some mess, not landing in the right place, + // (and there's compounding scale issues on dragging the canvas) dt.writeTransform(menu, { s: 1, x: ((evt.clientX - pt.x) / pt.s), // (pt.s + -0.1 * (pt.s-1))), y: ((evt.clientY - pt.y) / pt.s) // + -0.1 * (pt.s-1))) }) + // $(this.plane).append(menu) - writeMessage([MK.REQLISTAVAIL]) + // hmmm + this.changeContextTitle('you can... ') + // on of the options will ... + // add a hunk menu + this.addContextOption('add a hunk', (evt) => { + msgbox.write('requested a list of hunks...') + $(evt.target).text('requested a list of hunks...') + writeMessage([MK.REQLISTAVAIL]) + }) + + this.addContextOption('load a patch', (evt) => { + $(evt.target).append(' loading a list...') + patchset.findPatches() + }) + + this.addContextOption('save this patch', (evt) => { + $(evt.target).append(' > input for the name > ') + patchset.saveCurrent(evt, true) + }) + // writeMessage([MK.REQLISTAVAIL]) } - let addContextOptions = (list) => { - let menu = $(this.plane).children('.contextmenu').get(0) - for (let option of list) { - $(menu).append(writeContextOption(option)) + // takes 'under' argument + this.addContextOption = (text, click) => { + $(this.plane).find('.contextmenu').get(0).append($('<li>' + text + '</li>').click((click)).get(0)) + } + + this.changeContextTitle = (text) => { + // clear, + $(this.plane).find('.contextmenu').children().remove() + // overkill, but fun + let menu = $(this.plane).find('.contextmenu').get(0) + let title = $(`<div>${text}</div>`).addClass('contextTitle').get(0) + title.onmousedown = (evt) => { + evt.preventDefault() + evt.stopPropagation() + let domElemMouseMove = (evt) => { + // TRANSFORMS here to move div about on drag + evt.preventDefault() + evt.stopPropagation() + let ct = dt.readTransform(menu) + let pt = dt.readTransform(menu.parentElement) // think that's just this.plane ? + ct.x += evt.movementX / pt.s + ct.y += evt.movementY / pt.s + dt.writeTransform(menu, ct) + this.drawLinks() + } + + function rmOnMouseUp(evt) { + document.removeEventListener('mousemove', domElemMouseMove) + document.removeEventListener('mouseup', rmOnMouseUp) + } + document.addEventListener('mousemove', domElemMouseMove) + document.addEventListener('mouseup', rmOnMouseUp) } + $(this.plane).find('.contextmenu').append(title) } - let writeContextOption = (text) => { - let item = $('<li>' + text + '</li>').get(0) - item.addEventListener('click', (evt) => { - // SIP: serialize in place ... haha - let msg = new Array() - msg.push(MK.REQADDHUNK) - MSGS.writeTo(msg, text, 'string') + /* + this.changeContextTitle('list of available:') + for(let item of list){ + this.addContextOption(item, (evt) => { + let msg = [MK.REQADDHUNK] + MSGS.writeTo(msg, item, 'string') writeMessage(msg) - $(item).append(' > requested ...') + $(evt.target).append(' > requested ... ') }) - return item } - + */ /* --------------------------- ---------------------------- */ /* ---------------------- FORCE LAYOUT ----------------------- */ @@ -424,9 +476,9 @@ function View() { if ($(nd).attr('id') === "NROL39_0" || $(nd).attr('id') === "TLView") { //console.log('skip') } else { - let ps = dt.readXY(nd) - ps.id = nd.id - positions.push(ps) + let pos = dt.readXY(nd) + pos.id = nd.id + positions.push(pos) } } return positions @@ -440,9 +492,9 @@ function View() { if ($(nd).attr('id') === "NROL39_0" || $(nd).attr('id') === "TLView") { //console.log('skip') } else { - let ps = dt.readSize(nd) - ps.id = nd.id - sizes.push(ps) + let sz = dt.readSize(nd) + sz.id = nd.id + sizes.push(sz) } } return sizes @@ -854,7 +906,15 @@ function View() { break case MK.LISTOFAVAIL: let stringlist = MSGS.readListFrom(msg, 1, 'string') - addContextOptions(stringlist) + this.changeContextTitle('list of available:') + for (let item of stringlist) { + this.addContextOption(item, (evt) => { + let msg = [MK.REQADDHUNK] + MSGS.writeTo(msg, item, 'string') + writeMessage(msg) + $(evt.target).append(' > requested ... ') + }) + } break case MK.HUNKALIVE: console.log('hunk alive, going to deserialize') diff --git a/style.css b/style.css index d5c0c1a..10a89cc 100644 --- a/style.css +++ b/style.css @@ -165,6 +165,10 @@ body { cursor: grab; } +.blockid:active{ + cursor: grabbing; +} + .inputs { width: 117px; float: left; @@ -197,6 +201,11 @@ body { color: #eee; } +.stateItem { + font-size: 11px; + padding: 3px; +} + .uidiv { width: 396px; padding-top: 5px; @@ -254,12 +263,31 @@ li { li:hover{ background-color: #969696; + cursor: pointer; } li:active{ background-color: #d1d1d1; } +.contextTitle { + font-size: 14px; + font-weight: bold; + font-style: italic; + color: #eee; + padding: 7px 5px 6px 5px; +} + +.contextTitle:hover { + background-color: #969696; + cursor: grab; +} + +.contextTitle:active { + background-color: #d1d1d1; + cursor: grabbing; +} + /* USING THESE WITHIN BOYOS */ .cuttlefishhunkdom { diff --git a/typeset.js b/typeset.js index 783b17a..d82b473 100644 --- a/typeset.js +++ b/typeset.js @@ -122,7 +122,7 @@ const TSET = [{ if(arr[start] !== this.key) throw new Error(`mismatched key on phy read: ${arr[start]}, ${this.key}`) let rdarr = arr.slice(start + 1, start + 5).reverse() let btarr = Uint8Array.from(rdarr) - console.log('bts on read', btarr) + console.log('bts on read of uint32', btarr) // now make uint32 view on this ... let vlarr = new Uint32Array(btarr.buffer) console.log('vlarr', vlarr) @@ -131,6 +131,32 @@ const TSET = [{ increment: 5 } } + }, + { + name: 'number', + key: 40, + write: function(value){ + if (typeof value !== 'number') throw new Error('cannot cast non-number into physical world') + let tparr = new Float64Array(1) + tparr[0] = value + let btarr = new Uint8Array(tparr.buffer) + // place + let rtarr = Array.from(btarr).reverse() + rtarr.unshift(this.key) + return rtarr + }, + read: function(arr, start){ + if(arr[start] !== this.key) throw new Error(`mismatched key on phy read: ${arr[start]}, ${this.key}`) + let rdarr = arr.slice(start + 1, start + 9).reverse() + let btarr = Uint8Array.from(rdarr) + console.log('bts on read of float64', btarr) + let vlarr = new Float64Array(btarr.buffer) + console.log('vlarr', vlarr) + return { + item: vlarr[0], + increment: 9 + } + } } // etc ] diff --git a/view/vdom.js b/view/vdom.js index 7ed1c0a..0fa53fd 100644 --- a/view/vdom.js +++ b/view/vdom.js @@ -72,7 +72,7 @@ function DomTools(View) { $(de).addClass('block').attr('id', def.id) // more html: the title - $(de).append($('<div>' + de.id + '</div>').addClass('blockid').append('<span style="float:right;"> (' + def.name + ')</span>')) + $(de).append($('<div>' + de.id + '</div>').addClass('blockid').append('<span style="float:right;">(' + def.name + ')</span>')) let title = $(de).children('.blockid').get(0) @@ -267,7 +267,7 @@ function DomTools(View) { // write those messy state objects let writeStateDom = (state, def) => { - let dom = $('<li><p>' + state.name + " (" + state.type + ")" + '</p></li>').get(0) + let dom = $('<div><p>' + state.name + " (" + state.type + ")" + '</p></div>').addClass('stateItem').get(0) dom.id = def.id + '_state_' + state.name switch (typeof state.value) { case 'string': diff --git a/view/vptch.js b/view/vptch.js new file mode 100644 index 0000000..a711a9a --- /dev/null +++ b/view/vptch.js @@ -0,0 +1,127 @@ +// patches are programs that are *incomplete without you* + +function PatchSet(View, MsgBox){ + let view = View + let msgbox = MsgBox + + this.init = () => { + msgbox.write('hello from patchset') + } + + // the issue you're worrying about is: + /* + what of these hunks that will autoload each time, the bootstraps? + ... np, fam, when we send a request to the manager to add them, + managers should just reply w/ an error - we have paths for that + this is a bug we can iron out later and ignore + */ + this.saveCurrent = (evt, debug) => { + if(debug) console.log('saving ...') + // riperoni ok + let patch = { + hunks: [], + links: [] + } + // js, u wyld + for(let hnk of $(view.plane).children('.block')){ + // dom is truth + if(debug) console.log('hnk', hnk) + let name = $(hnk).children('.blockid').find('span').text() + name = name.substring(1, name.length - 1) + let phnk = { + id: hnk.id, + name: name + } + let state = [] + for(let st of $(hnk).children('.state').children('.stateItem')){ + // text is faithful, + let text = $(st).find('p').text() + let name = text.substring(0, text.indexOf(' ')) + let type = text.substring(text.indexOf('(') + 1, text.indexOf(')')) + if(debug) console.log('state: name', `"${name}"`, 'type', `"${type}"`) + // the value... (typing on program saves? not if we JSON ...) + let value + if(type === 'boolean'){ + let vstring = $(st).find('span').text() + vstring = vstring.substring(vstring.indexOf('(') + 1, vstring.indexOf(')')) + if(vstring === 'true'){ + value = true + } else if (vstring === 'false'){ + value = false + } else { + console.error('error saving boolean value, setting to false') + value = false + } + } else if (type === 'string') { + value = $(st).find('input').val() + } else { + // must be some kind of number, + value = parseFloat($(st).find('input').val()) + }// end if-on-types sequence + state.push({ + name: name, + type: type, + value: value + }) + } // end roll over states, + if(state.length > 0){ + phnk.state = state + } + patch.hunks.push(phnk) + // now roll over links in the hunk, to write outputs + for(let otp of $(hnk).children('.outputs').children('.output')){ + if(debug) console.log('and output', otp) + let outId = otp.id.substring(0, otp.id.indexOf('_output_')) + let outName = otp.id.substring(otp.id.indexOf('_output_') + 8) + for(let conn of otp.connectedTo){ + let inId = conn.substring(1, conn.indexOf('_input_')) + let inName = conn.substring(conn.indexOf('_input_') + 7) + patch.links.push({ + outhunk: outId, + outname: outName, + inhunk: inId, + inname: inName + }) + } + } // end loop over outputs, for links ... + } // end loop over hunks + // we have this now, + if(debug) console.log('a patch', patch) + // prompt for name? ... via the (evt) on the callback ?? + $(evt.target).text('') + let tinput = $('<input>').attr('type', 'text').attr('size', 24).attr('value', 'patch').get(0) + $(evt.target).append(tinput) // etc + $(tinput).focus() + $(tinput).select() + $(tinput).on('keyup', (evt) => { + if(evt.keyCode == 13){ + console.log('yar, ', tinput.value + '.json') + let bleb = JSON.stringify(patch) + console.log('tryit...') + let url = URL.createObjectURL(new Blob([JSON.stringify(patch)], {type: "application/json"})) + //window.location.href = url + console.log('url', url) + let anchor = $('<a>ok</a>').attr('href', url).attr('download', tinput.value+ '.json').get(0) + console.log(anchor) + $(evt.target).append(anchor) + anchor.click() + // finally, rip + $(view.plane).find('.contextmenu').remove() + //saveAs(bleb, 'file.json') + } + }) + // should name it, and ID it for the interpeter ? + } + + // load from server should be assumed, just rip that *baybie* + this.findPatches = () => { + msgbox.write('would look for list') + } + + this.loadPatch = (name) => { + + } + +} + +export default PatchSet -- GitLab