From: Brendan Hansen Date: Mon, 6 Sep 2021 03:53:02 +0000 (-0500) Subject: added a canvas with a basic API for now X-Git-Url: https://git.brendanfh.com/?a=commitdiff_plain;h=4979cca8263c1076ebecadcae1e79ad3d67dabc4;p=onyx-live.git added a canvas with a basic API for now --- diff --git a/canvas.onyx b/canvas.onyx new file mode 100644 index 0000000..07e830e --- /dev/null +++ b/canvas.onyx @@ -0,0 +1,13 @@ +package canvas + +init :: () -> void #foreign "canvas" "init" --- +clear :: () -> void #foreign "canvas" "clear" --- +set_fill_style :: (style: str) -> void #foreign "canvas" "set_fill_style" --- +fill_rect :: (x: i32, y: i32, w: i32, h: i32) -> void #foreign "canvas" "fill_rect" --- + +get_size_internal :: (out_width: ^i32, out_height: ^i32) -> void #foreign "canvas" "get_size" --- +get_size :: () -> (i32, i32) { + sx, sy: i32; + get_size_internal(^sx, ^sy); + return sx, sy; +} diff --git a/serve.py b/serve.py index b5e5219..4a8dc43 100644 --- a/serve.py +++ b/serve.py @@ -56,7 +56,7 @@ def post_compile_onyx(): with os.fdopen(code_file_desc, "w+b") as code_file: code_file.write(code.encode('utf-8')) - compile_process = subprocess.run(f"timeout -s KILL 10s onyx -r js --no-file-contents --no-colors -o {wasm_file_name} {code_file_name} ./read_line.onyx", shell=True, capture_output=True) + compile_process = subprocess.run(f"timeout -s KILL 10s onyx -r js --no-file-contents --no-colors -o {wasm_file_name} {code_file_name} ./read_line.onyx ./canvas.onyx", shell=True, capture_output=True) os.remove(code_file_name) diff --git a/static/css/index.css b/static/css/index.css index 79ae516..11c5299 100644 --- a/static/css/index.css +++ b/static/css/index.css @@ -1,8 +1,9 @@ :root { --menu-bar-height: 32px; - --input-bar-height: 32px; + --input-bar-height: 48px; --divider-size: 4px; --left-half-width: 70%; + --top-half-height: 30%; } * { @@ -110,7 +111,7 @@ select:hover { #code-result { height: 100vh; - max-height: calc(100vh - var(--menu-bar-height) - var(--input-bar-height)); /* subtract the padding */ + max-height: calc(100vh - var(--menu-bar-height) - var(--input-bar-height) - var(--top-half-height) - var(--divider-size)); /* subtract the padding */ background: var(--terminal-background-color); color: var(--terminal-foreground-color); @@ -138,6 +139,16 @@ select:hover { float: left; } +#vertical-divider { + width: 100%; + height: var(--divider-size); + background-color: #777; + cursor: row-resize; + + display: inline-block; + float: left; +} + #input-bar { background-color: var(--background-color); color: var(--foreground-color); @@ -153,6 +164,11 @@ select:hover { font-family: Monaco, Menlo, "Ubuntu Mono", Consolas, source-code-pro, monospace; } +#render-target { + width: 100%; + height: var(--top-half-height); +} + .jquery-modal.blocker.current { z-index: 100 !important; } diff --git a/static/src/canvas.js b/static/src/canvas.js new file mode 100644 index 0000000..fa9c98f --- /dev/null +++ b/static/src/canvas.js @@ -0,0 +1,46 @@ +let canvas_element = ""; +let ctx = null; + +function update_canvas_size() { + let canvas_data = new Int32Array(canvas_shared_buffer); + let box = canvas_element.getBoundingClientRect(); + + canvas_element.width = box.width; + canvas_element.height = box.height; + + Atomics.store(canvas_data, 0, box.width); + Atomics.store(canvas_data, 1, box.height); + Atomics.store(canvas_data, 2, 1); + Atomics.notify(canvas_data, 2); +} + +function canvas_handler(instr) { + switch (instr[0]) { + case 'init': { + canvas_element = document.getElementById("render-target"); + ctx = canvas_element.getContext('2d'); + update_canvas_size(); + break; + } + + case 'set_fill_style': { + ctx.fillStyle = instr[1]; + break; + } + + case 'fill_rect': { + ctx.fillRect(instr[1], instr[2], instr[3], instr[4]); + let canvas_data = new Int32Array(canvas_shared_buffer); + + // TODO: Do I need to synchonize the worker thread and the master thread? + Atomics.store(canvas_data, 2, 1); + Atomics.notify(canvas_data, 2); + break; + } + + case 'clear': { + ctx.clearRect(0, 0, canvas_element.width, canvas_element.height); + break; + } + } +} diff --git a/static/src/index.js b/static/src/index.js index 8bd78c0..b7bd57f 100644 --- a/static/src/index.js +++ b/static/src/index.js @@ -3,7 +3,8 @@ let editor_keybind_mode = "normal"; let editor_theme = "chrome"; let ui_theme = "dark"; -let input_shared_buffer = new SharedArrayBuffer(1024 * Uint8Array.BYTES_PER_ELEMENT); +let input_shared_buffer = new SharedArrayBuffer(1024 * Uint8Array.BYTES_PER_ELEMENT); +let canvas_shared_buffer = new SharedArrayBuffer(3 * Int32Array.BYTES_PER_ELEMENT); async function clear_output() { let elem = document.getElementById('code-result'); @@ -46,11 +47,19 @@ async function run_wasm(wasm_bytes) { update_running_msg(); break; } + + case 'canvas': { + canvas_handler(e.data.data); + } } }; - wasm_worker.postMessage({ type: 'set_buffer', data: input_shared_buffer }); - wasm_worker.postMessage({ type: 'start', data: wasm_bytes }); + wasm_worker.postMessage({ + type: 'set_buffers', + input_buffer: input_shared_buffer, + canvas_buffer: canvas_shared_buffer, + }); + wasm_worker.postMessage({ type: 'start', data: wasm_bytes }); update_running_msg(); } @@ -260,10 +269,12 @@ window.onload = () => { populate_examples(); load_settings(); - make_resizer("horizontal-divider", "--left-half-width", (e) => { + make_resizer("horizontal-divider", "--left-half-width", "", (e) => { editor.resize(true); }); + make_resizer("vertical-divider", "", "--top-half-height", null); + document.getElementById("input-bar").addEventListener("keyup", (ev) => { if (ev.keyCode === 13) { submit_input(); diff --git a/static/src/resizer.js b/static/src/resizer.js index 1cc98fb..e748d07 100644 --- a/static/src/resizer.js +++ b/static/src/resizer.js @@ -1,4 +1,4 @@ -function make_resizer(divider_id, css_prop_name, on_resize) { +function make_resizer(divider_id, css_width_prop_name, css_height_prop_name, on_resize) { const elem = document.getElementById(divider_id); const left_elem = elem.previousElementSibling; const right_elem = elem.nextElementSibling; @@ -7,14 +7,23 @@ function make_resizer(divider_id, css_prop_name, on_resize) { let mx = 0; let my = 0; let left_width = 0; + let top_height = 0; const mouse_move_handler = (e) => { const dx = e.clientX - mx; const dy = e.clientY - my; - const pw = elem.parentNode.getBoundingClientRect().width; - const lw = 100 * Math.min(pw - 10, Math.max(10, (left_width + dx))) / pw; - root.style.setProperty(css_prop_name, `${lw}%`); + if (css_width_prop_name != null) { + const pw = elem.parentNode.getBoundingClientRect().width; + const lw = 100 * Math.min(pw - 10, Math.max(10, (left_width + dx))) / pw; + root.style.setProperty(css_width_prop_name, `${lw}%`); + } + + if (css_height_prop_name != null) { + const ph = elem.parentNode.getBoundingClientRect().height; + const th = 100 * Math.min(ph - 10, Math.max(10, (top_height + dy))) / ph; + root.style.setProperty(css_height_prop_name, `${th}%`); + } document.body.style.cursor = 'col-resize'; @@ -44,6 +53,7 @@ function make_resizer(divider_id, css_prop_name, on_resize) { mx = e.clientX; my = e.clientY; left_width = left_elem.getBoundingClientRect().width; + top_height = left_elem.getBoundingClientRect().height; document.addEventListener("mousemove", mouse_move_handler); document.addEventListener("mouseup", mouse_up_handler); diff --git a/static/src/storage.js b/static/src/storage.js index 49be20f..8edd14f 100644 --- a/static/src/storage.js +++ b/static/src/storage.js @@ -1,20 +1,27 @@ function refresh_file_lists(callback) { $(".file-list").empty(); + let filenames = []; let $lists = $(".file-list"); for (let i=0; i < localStorage.length; i++) { let name = localStorage.key(i); if (name.startsWith("saved_")) { let filename = name.substr(6); - let $button = $(``); - $button.on('click', (ev) => callback(filename)); + filenames.push(filename); + } + } - let $delete_button = $(``); - $delete_button.on('click', (ev) => delete_from_local_storage_with_name(filename, callback)); + filenames.sort(); - $lists.append($button); - $lists.append($delete_button); - } + for (let filename of filenames) { + let $button = $(``); + $button.on('click', (ev) => callback(filename)); + + let $delete_button = $(``); + $delete_button.on('click', (ev) => delete_from_local_storage_with_name(filename, callback)); + + $lists.append($button); + $lists.append($delete_button); } } diff --git a/static/src/worker.js b/static/src/worker.js index 686d20c..70bd4e3 100644 --- a/static/src/worker.js +++ b/static/src/worker.js @@ -1,4 +1,5 @@ let input_shared_buffer = null; +let canvas_data_buffer = null; let wasm_memory = null; let import_obj = { @@ -38,13 +39,51 @@ let import_obj = { self.postMessage({ type: 'terminated' }); self.close(); }, + }, + + canvas: { + init() { + self.postMessage({ type: 'canvas', data: [ 'init' ] }); + + let canvas_data = new Int32Array(canvas_data_buffer); + Atomics.wait(canvas_data, 2, 0); + Atomics.store(canvas_data, 2, 0); + }, + + clear() { + self.postMessage({ type: 'canvas', data: [ 'clear' ] }); + }, + + get_size(outwidth, outheight) { + let data = new DataView(wasm_memory.buffer); + let canvas_data = new Int32Array(canvas_data_buffer); + + data.setInt32(outwidth, Atomics.load(canvas_data, 0), true); + data.setInt32(outheight, Atomics.load(canvas_data, 1), true); + }, + + set_fill_style(styleptr, stylelen) { + let strdata = new Uint8Array(wasm_memory.buffer, styleptr, stylelen); + let str = new TextDecoder().decode(strdata); + + self.postMessage({ type: 'canvas', data: [ 'set_fill_style', str ] }); + }, + + fill_rect(x, y, w, h) { + self.postMessage({ type: 'canvas', data: [ 'fill_rect', x, y, w, h ] }); + + let canvas_data = new Int32Array(canvas_data_buffer); + Atomics.wait(canvas_data, 2, 0); + Atomics.store(canvas_data, 2, 0); + } } }; onmessage = function(m) { switch (m.data.type) { - case 'set_buffer': { - input_shared_buffer = m.data.data; + case 'set_buffers': { + input_shared_buffer = m.data.input_buffer; + canvas_data_buffer = m.data.canvas_buffer; break; } diff --git a/templates/index.html b/templates/index.html index 84860ca..98e5f0e 100644 --- a/templates/index.html +++ b/templates/index.html @@ -11,6 +11,7 @@ + @@ -43,9 +44,13 @@ main :: (args: [] cstr) { } -
+
+ + +
+