From 8b978848ff462b16457406af3f0a293ee0f8c2d9 Mon Sep 17 00:00:00 2001 From: Leon van Kammen Date: Fri, 28 Jun 2024 18:01:24 +0200 Subject: [PATCH] add window.js + autolaunch + update isoterminal scale --- com/dom.js | 2 +- com/isoterminal.js | 134 ++++++--------------------------------------- com/launcher.js | 14 ++--- com/window.js | 55 +++++++++++++++++++ 4 files changed, 80 insertions(+), 125 deletions(-) create mode 100644 com/window.js diff --git a/com/dom.js b/com/dom.js index cac678c..c16f90f 100644 --- a/com/dom.js +++ b/com/dom.js @@ -95,7 +95,7 @@ AFRAME.registerComponent('dom',{ assignUniqueID: function(){ // assign unique app id so it's easy to reference (by html-mesh component e.g.) - if( !this.el.uid ) this.el.uid = '_'+String(Math.random()).substr(10) + if( !this.el.uid ) this.el.uid = this.el.dom.id = '_'+String(Math.random()).substr(10) return this }, diff --git a/com/isoterminal.js b/com/isoterminal.js index aedb234..6868bdb 100644 --- a/com/isoterminal.js +++ b/com/isoterminal.js @@ -11,6 +11,7 @@ AFRAME.registerComponent('isoterminal', { }, requires:{ + 'window': "com/window.js", html: "https://unpkg.com/aframe-htmlmesh@2.1.0/build/aframe-html.js", // html to AFRAME winboxjs: "https://unpkg.com/winbox@0.2.82/dist/winbox.bundle.min.js", // deadsimple windows: https://nextapps-de.github.io/winbox winboxcss: "https://unpkg.com/winbox@0.2.82/dist/css/winbox.min.css", // @@ -21,11 +22,11 @@ AFRAME.registerComponent('isoterminal', { }, dom: { - scale: 3, + scale: 0.7, events: ['click','keydown'], html: (me) => `
- +
`, css: (me) => `.isoterminal{ @@ -44,48 +45,6 @@ AFRAME.registerComponent('isoterminal', { }` }, - createTerminal: async function(instance){ - const dom = instance.dom - //this.el.object3D.visible = true - - const term = this.term = new Terminal({ - allowTransparency: this.data.transparent, - cursorBlink: true, - disableStdin: false, - rows: this.data.rows, - cols: this.data.cols, - fontSize: 16 - }) - - term.open(dom) - this.canvas = dom.querySelector('.xterm-text-layer') - this.canvas.id = 'terminal-' + instance.uid - this.canvasContext = this.canvas.getContext('2d') - - this.cursorCanvas = dom.querySelector('.xterm-cursor-layer') - - //this.el.setAttribute('material', `transparent: ${this.data.transparent?'true':'false'}; src: #${this.canvas.id}` ) - - term.on('refresh', () => { - console.log("refresh") - }) - - term.on('data', (data) => { - console.log(data) - this.el.emit('xterm-data', data) - }) - - this.el.addEventListener('click', () => { - term.focus() - }) - - const message = 'Hello from \x1B[1;3;31mWebVR\x1B[0m !\r\n$ ' - term.write(message) - - this.runISO() - return {width: this.canvas.width, height: this.canvas.height } - }, - runISO: function(dom){ var emulator = window.emulator = new V86({ wasm_path: "com/isoterminal/v86.wasm", @@ -102,12 +61,12 @@ AFRAME.registerComponent('isoterminal', { cdrom: { url: this.data.iso, }, + network_relay_url: "", + cmdline: "rw root=host9p rootfstype=9p rootflags=trans=virtio,cache=loose modules=virtio_pci tsc=reliable init_on_free=on", //bzimage:{ // url: "com/isoterminal/images/buildroot-bzimage.bin" //}, - network_relay_url: "", //bzimage_initrd_from_filesystem: true, - cmdline: "rw root=host9p rootfstype=9p rootflags=trans=virtio,cache=loose modules=virtio_pci tsc=reliable init_on_free=on", //filesystem: { // baseurl: "com/isoterminal/v86/images/alpine-rootfs-flat", // basefs: "com/isoterminal/v86/images/alpine-fs.json", @@ -135,56 +94,23 @@ AFRAME.registerComponent('isoterminal', { // instance this component const instance = this.el.cloneNode(false) this.el.sceneEl.appendChild( instance ) -// instance.addEventListener('DOMready', () => { -// console.dir(instance) -// debugger -// this.runISO(instance.dom) -// }) + + instance.addEventListener('DOMready', () => { + this.runISO(instance.dom) + instance.setAttribute("window", `title: ${this.data.iso}; uid: ${instance.uid}; attach: #overlay; dom: #${instance.dom.id}`) + }) + + instance.addEventListener('window.onclose', (e) => { + if( !confirm('do you want to kill this virtual machine and all its processes?') ) e.halt = true + }) + instance.setAttribute("dom", "") instance.setAttribute("xd", "") // allows flipping between DOM/WebGL when toggling XD-button instance.setAttribute("visible", AFRAME.utils.XD() == '3D' ? 'true' : 'false' ) instance.setAttribute("position", AFRAME.utils.XD.getPositionInFrontOfCamera(0.5) ) - // instance.setAttribute("grabbable","") + instance.setAttribute("grabbable","") + instance.object3D.quaternion.copy( AFRAME.scenes[0].camera.quaternion ) // face towards camera - - const setupWindow = () => { - this.runISO(instance.dom) - const com = instance.components['isoterminal'] - instance.dom.style.display = 'none' - let winbox = new WinBox( this.data.iso, { - height:'50px', - x:"center", - y:"center", - id: instance.uid, // important hint for html-mesh - root: document.querySelector("#overlay"), - mount: instance.dom, - onclose: () => { - if( !confirm('do you want to kill this virtual machine and all its processes?') ) return true - instance.dom.style.display = 'none'; - return false - }, - oncreate: () => { - setTimeout( () => { - winbox.resize( winbox.width+'px', (instance.dom.offsetHeight+(2*15))+'px' ) - setTimeout( () => instance.setAttribute("html",`html:#${instance.uid}; cursor:#cursor`), 1000) - },100) - } - }); - instance.dom.style.display = '' // show - - // hint grabbable's obb-collider to track the window-object - instance.components['obb-collider'].data.trackedObject3D = 'components.html.el.object3D.children.0' - instance.components['obb-collider'].update() - - // data2event demo - //instance.setAttribute("data2event","") - //com.data.myvalue = 1 - //com.data.foo = `instance ${instance.uid}: ` - //setInterval( () => com.data.myvalue++, 500 ) - } - - setTimeout( () => setupWindow(), 10 ) // give new components time to init - }, }, @@ -242,29 +168,3 @@ in above's case "\nHelloworld application\n" will qualify as header. } }); - -AFRAME.registerComponent('xterm-shell', { - dependencies: ['xterm'], - init: function() { - const message = 'Run \x1B[1;3;31m\'node server.js\'\x1B[0m to open a shell\r\n' - const xterm = this.el.components['xterm'] - - xterm.write(message) - - const socket = new WebSocket('ws://localhost:8080/') - - // Listen on data, write it to the terminal - socket.onmessage = ({data}) => { - xterm.write(data) - } - - socket.onclose = () => { - xterm.write('\r\nConnection closed.\r\n') - } - - // Listen on user input, send it to the connection - this.el.addEventListener('xterm-data', ({detail}) => { - socket.send(detail) - }) - } -}) diff --git a/com/launcher.js b/com/launcher.js index b62ff67..26aa254 100644 --- a/com/launcher.js +++ b/com/launcher.js @@ -80,8 +80,8 @@ AFRAME.registerComponent('launcher', { dom: { scale: 3, events: ['click'], - html: (me) => `
loading components..
`, - css: (me) => `#iconmenu { + html: (me) => `
loading components..
`, + css: (me) => `.iconmenu { z-index: 1000; display: flex; flex-direction: row; @@ -98,7 +98,7 @@ AFRAME.registerComponent('launcher', { pointer-events: none; visibility: visible !important; } - #iconmenu > button { + .iconmenu > button { line-height:0px; pointer-events:all; width: 58px; @@ -112,27 +112,27 @@ AFRAME.registerComponent('launcher', { font-size:18px; } - #iconmenu > button:first-child { + .iconmenu > button:first-child { border-radius: 5px 0px 0px 5px; border-bottom: 2px solid #BBB; border-left: 2px solid #BBB; padding-bottom:16px; } - #iconmenu > button:last-child { + .iconmenu > button:last-child { border-radius:0px 5px 5px 0px; border-top: 2px solid #BBB; border-right: 2px solid #BBB; padding-top:13px; } - #iconmenu > button > img { + .iconmenu > button > img { transform: translate(0px,-14px); opacity:0.5; padding: 5px; border-radius: 0px; } - #iconmenu > button > img:hover{ + .iconmenu > button > img:hover{ background: #AAA; transition:0.gg3s; border-radius: 50%; diff --git a/com/window.js b/com/window.js new file mode 100644 index 0000000..fac3780 --- /dev/null +++ b/com/window.js @@ -0,0 +1,55 @@ +AFRAME.registerComponent('window', { + schema:{ + title: {type:'string',"default":"title"}, + width: {type:'string'}, // wrap + height: {type:'string',"default":'50px'}, + uid: {type:'string'}, + attach: {type:'selector'}, + dom: {type:'selector'}, + x: {type:'string',"default":"center"}, + y: {type:'string',"default":"center"} + }, + + dependencies:['dom'], + + init: function(){ + setTimeout( () => this.setupWindow(), 10 ) // init after other components + }, + + setupWindow: function(){ + if( !this.el.dom ) return console.error('window element requires dom-component as dependency') + + this.el.dom.style.display = 'none' + let winbox = new WinBox( this.data.title, { + height:this.data.height, + height:this.data.width, + x: this.data.x, + y: this.data.y, + id: this.data.uid || String(Math.random()).substr(4), // important hint for html-mesh + root: this.data.attach || document.body, + mount: this.data.dom, + oncreate: () => { + this.el.emit('window.oncreate',{}) + // resize after the dom content has been rendered & updated + setTimeout( () => { + winbox.resize( winbox.width+'px', (this.data.dom.offsetHeight+(2*15))+'px' ) + setTimeout( () => this.el.setAttribute("html",`html:#${this.data.uid}; cursor:#cursor`), 1000) + this.el.setAttribute("grabbable","") + },1000) + }, + onclose: () => { + let e = {halt:false} + this.el.emit('window.onclose',e) + if( e.halt ) return true + this.data.dom.style.display = 'none'; + return false + }, + }); + this.data.dom.style.display = '' // show + + // hint grabbable's obb-collider to track the window-object + this.el.components['obb-collider'].data.trackedObject3D = 'components.html.el.object3D.children.0' + this.el.components['obb-collider'].update() + + } +})