From 168472cff8b5c4f4d87358656005849cf966e27f Mon Sep 17 00:00:00 2001 From: Hugo H Date: Thu, 25 Dec 2025 15:24:35 +0000 Subject: [PATCH] Redesigned the editor, and added the canvas library --- editor.html | 383 ++++++++++++++++++++++++++++++++++++---------------- screen.js | 226 +++++++++++++++++++++++++++++++ 2 files changed, 495 insertions(+), 114 deletions(-) create mode 100644 screen.js diff --git a/editor.html b/editor.html index 7a6695e..51da164 100644 --- a/editor.html +++ b/editor.html @@ -1,124 +1,225 @@ + Code Editor + + + -
-
- +
+
+ + +
-
-
-
-
+ -
- -
-
-

main.py

- - +
+
+
+
+
-
- -
- +
+
- -
+
+ + \ No newline at end of file diff --git a/screen.js b/screen.js new file mode 100644 index 0000000..81d8e1a --- /dev/null +++ b/screen.js @@ -0,0 +1,226 @@ +window.onerror = function (message, source, lineno, colno, error) { + if (window.outf) window.outf(`[JS Error] ${message} at ${source}:${lineno}:${colno}\n`); + return false; +}; + +var $builtinmodule = function (name) { + var mod = {}; + + var lc_instance = null; + var python_callbacks = {}; + + function toJS(obj) { + if (obj === undefined || obj === null) return obj; + if (obj instanceof Sk.builtin.int_ || obj instanceof Sk.builtin.float_) { + return Sk.ffi.remapToJs(obj); + } + if (obj instanceof Sk.builtin.str) return obj.v; + if (obj instanceof Sk.builtin.bool) return obj.v; + if (obj instanceof Sk.builtin.list || obj instanceof Sk.builtin.tuple || obj instanceof Sk.builtin.dict) { + return Sk.ffi.remapToJs(obj); + } + return obj; + } + + function toPy(obj) { + if (obj === undefined || obj === null) return Sk.builtin.none.none$; + if (typeof obj === 'number') { + return (obj % 1 === 0) ? new Sk.builtin.int_(obj) : new Sk.builtin.float_(obj); + } + if (typeof obj === 'string') return new Sk.builtin.str(obj); + if (typeof obj === 'boolean') return obj ? Sk.builtin.bool.true$ : Sk.builtin.bool.false$; + if (Array.isArray(obj)) return new Sk.builtin.list(obj.map(toPy)); + return obj; + } + + function makePyCallback(pyFunc) { + if (!pyFunc || pyFunc === Sk.builtin.none.none$) return null; + return function (...args) { + var pyArgs = args.map(toPy); + return Sk.misceval.callsimArray(pyFunc, pyArgs); + }; + } + + function getDictItem(skDict, keyStr) { + if (!skDict || !(skDict instanceof Sk.builtin.dict)) return null; + const key = new Sk.builtin.str(keyStr); + return skDict.mp$lookup(key); + } + + mod.start = new Sk.builtin.func(function (settings) { + let jsSettings = {}; + var loopInit = null; + var loopUpdate = null; + var loopDraw = null; + var loopResized = null; + var loopTap = null; + var loopUntap = null; + var loopTapping = null; + var loopTapped = null; + + if (settings && settings !== Sk.builtin.none.none$) { + jsSettings = toJS(settings); + if (settings instanceof Sk.builtin.dict) { + var loopDict = getDictItem(settings, 'loop'); + if (loopDict && loopDict instanceof Sk.builtin.dict) { + loopInit = getDictItem(loopDict, 'init'); + loopUpdate = getDictItem(loopDict, 'update'); + loopDraw = getDictItem(loopDict, 'draw'); + loopResized = getDictItem(loopDict, 'resized'); + loopTap = getDictItem(loopDict, 'tap'); + loopUntap = getDictItem(loopDict, 'untap'); + loopTapping = getDictItem(loopDict, 'tapping'); + loopTapped = getDictItem(loopDict, 'tapped'); + } + } + } + + if (!jsSettings.canvas) jsSettings.canvas = '#canvas'; + const canvasEl = document.querySelector(jsSettings.canvas); + if (canvasEl) { + const rect = canvasEl.getBoundingClientRect(); + canvasEl.width = rect.width || canvasEl.clientWidth; + canvasEl.height = rect.height || canvasEl.clientHeight; + + jsSettings.width = Math.floor(canvasEl.clientWidth); + jsSettings.height = Math.floor(canvasEl.clientHeight); + jsSettings.canvas = canvasEl; + jsSettings.fullscreen = false; + jsSettings.autoscale = false; + } + + if (jsSettings.autoscale === undefined) jsSettings.autoscale = false; + + var jsLoop = jsSettings.loop || {}; + python_callbacks = { + init: loopInit || jsLoop.init, + update: loopUpdate || jsLoop.update, + draw: loopDraw || jsLoop.draw, + resized: loopResized || jsLoop.resized, + tap: loopTap || jsLoop.tap, + untap: loopUntap || jsLoop.untap, + tapping: loopTapping || jsLoop.tapping, + tapped: loopTapped || jsLoop.tapped + }; + + jsSettings.loop = { + init: python_callbacks.init ? makePyCallbackNoArgs(python_callbacks.init) : null, + update: python_callbacks.update ? makePyCallbackNoArgs(python_callbacks.update) : null, + draw: python_callbacks.draw ? makeSafePyCallbackNoArgs(python_callbacks.draw) : null, + resized: python_callbacks.resized ? makePyCallback(python_callbacks.resized) : null, + tap: python_callbacks.tap ? makePyCallbackTapArgs(python_callbacks.tap) : null, + untap: python_callbacks.untap ? makePyCallbackTapArgs(python_callbacks.untap) : null, + tapping: python_callbacks.tapping ? makePyCallbackTapArgs(python_callbacks.tapping) : null, + tapped: python_callbacks.tapped ? makePyCallbackTapArgs(python_callbacks.tapped) : null + }; + + if (typeof litecanvas === 'undefined') { + throw new Sk.builtin.ImportError("litecanvas library not found."); + } + + try { + lc_instance = litecanvas(jsSettings); + window.__lc_instance = lc_instance; + } catch (e) { + if (window.outf) window.outf(`[litecanvas] Error: ${e}\n`); + throw e; + } + return Sk.builtin.none.none$; + }); + + function makeSafePyCallbackNoArgs(pyFunc) { + if (!pyFunc || pyFunc === Sk.builtin.none.none$) return null; + return function () { + try { return Sk.misceval.callsimArray(pyFunc, []); } + catch (e) { + if (window.outf) window.outf(`[Error] ${e}\n`); + if (lc_instance) lc_instance.pause(); + throw e; + } + }; + } + + function makePyCallbackNoArgs(pyFunc) { + if (!pyFunc || pyFunc === Sk.builtin.none.none$) return null; + return function () { return Sk.misceval.callsimArray(pyFunc, []); }; + } + + function makePyCallbackTapArgs(pyFunc) { + if (!pyFunc || pyFunc === Sk.builtin.none.none$) return null; + return function (x, y, id) { + const el = document.getElementById('canvas'); + let lx = x; + let ly = y; + if (el) { + const rect = el.getBoundingClientRect(); + // Map from window coordinates to canvas local coordinates + lx = (x - rect.left) * (el.width / rect.width); + ly = (y - rect.top) * (el.height / rect.height); + } + var pyArgs = [lx, ly, id].map(toPy); + return Sk.misceval.callsimArray(pyFunc, pyArgs); + }; + } + + Object.defineProperty(mod, 'T', { get: function () { return toPy(typeof T !== 'undefined' ? T : 0); } }); + Object.defineProperty(mod, 'W', { get: function () { return toPy(typeof W !== 'undefined' ? W : 0); } }); + Object.defineProperty(mod, 'H', { get: function () { return toPy(typeof H !== 'undefined' ? H : 0); } }); + Object.defineProperty(mod, 'MX', { + get: function () { + if (typeof MX === 'undefined') return toPy(-1); + const el = document.getElementById('canvas'); + if (!el) return toPy(MX); + const r = el.getBoundingClientRect(); + return toPy((MX - r.left) * (el.width / r.width)); + } + }); + Object.defineProperty(mod, 'MY', { + get: function () { + if (typeof MY === 'undefined') return toPy(-1); + const el = document.getElementById('canvas'); + if (!el) return toPy(MY); + const r = el.getBoundingClientRect(); + return toPy((MY - r.top) * (el.height / r.height)); + } + }); + Object.defineProperty(mod, 'CENTERX', { get: function () { return toPy(typeof CENTERX !== 'undefined' ? CENTERX : 0); } }); + Object.defineProperty(mod, 'CENTERY', { get: function () { return toPy(typeof CENTERY !== 'undefined' ? CENTERY : 0); } }); + + mod.PI = toPy(Math.PI); + mod.TWO_PI = toPy(Math.PI * 2); + mod.HALF_PI = toPy(Math.PI / 2); + + mod.cls = new Sk.builtin.func((c) => { cls(c !== undefined ? toJS(c) : undefined); return Sk.builtin.none.none$; }); + mod.rectfill = new Sk.builtin.func((x, y, w, h, c) => { rectfill(toJS(x), toJS(y), toJS(w), toJS(h), c !== undefined ? toJS(c) : 0); return Sk.builtin.none.none$; }); + mod.rect = new Sk.builtin.func((x, y, w, h, c) => { rect(toJS(x), toJS(y), toJS(w), toJS(h), c !== undefined ? toJS(c) : 0); return Sk.builtin.none.none$; }); + mod.circfill = new Sk.builtin.func((x, y, r, c) => { circfill(toJS(x), toJS(y), toJS(r), c !== undefined ? toJS(c) : 0); return Sk.builtin.none.none$; }); + mod.circ = new Sk.builtin.func((x, y, r, c) => { circ(toJS(x), toJS(y), toJS(r), c !== undefined ? toJS(c) : 0); return Sk.builtin.none.none$; }); + mod.text = new Sk.builtin.func((x, y, t, c, s) => { text(toJS(x), toJS(y), toJS(t), c !== undefined ? toJS(c) : 3, s !== undefined ? toJS(s) : 'normal'); return Sk.builtin.none.none$; }); + mod.textsize = new Sk.builtin.func((s) => { textsize(toJS(s)); return Sk.builtin.none.none$; }); + + mod.ovalfill = new Sk.builtin.func((x, y, rx, ry, c) => { ovalfill(toJS(x), toJS(y), toJS(rx), toJS(ry), c !== undefined ? toJS(c) : 0); return Sk.builtin.none.none$; }); + mod.line = new Sk.builtin.func((x1, y1, x2, y2, c) => { line(toJS(x1), toJS(y1), toJS(x2), toJS(y2), c !== undefined ? toJS(c) : 0); return Sk.builtin.none.none$; }); + mod.linewidth = new Sk.builtin.func((v) => { linewidth(toJS(v)); return Sk.builtin.none.none$; }); + mod.push = new Sk.builtin.func(() => { push(); return Sk.builtin.none.none$; }); + mod.pop = new Sk.builtin.func(() => { pop(); return Sk.builtin.none.none$; }); + mod.translate = new Sk.builtin.func((x, y) => { translate(toJS(x), toJS(y)); return Sk.builtin.none.none$; }); + mod.scale = new Sk.builtin.func((x, y) => { window.scale(toJS(x), y !== undefined ? toJS(y) : undefined); return Sk.builtin.none.none$; }); + mod.rotate = new Sk.builtin.func((r) => { rotate(toJS(r)); return Sk.builtin.none.none$; }); + mod.alpha = new Sk.builtin.func((v) => { alpha(toJS(v)); return Sk.builtin.none.none$; }); + mod.fill = new Sk.builtin.func((c) => { fill(toJS(c)); return Sk.builtin.none.none$; }); + mod.stroke = new Sk.builtin.func((c) => { window.stroke(toJS(c)); return Sk.builtin.none.none$; }); + mod.sfx = new Sk.builtin.func((p, ps, vf) => { var r = sfx(toJS(p), ps ? toJS(ps) : 0, vf ? toJS(vf) : 1); return r ? toPy(r) : Sk.builtin.bool.false$; }); + mod.volume = new Sk.builtin.func((v) => { volume(toJS(v)); return Sk.builtin.none.none$; }); + mod.iskeydown = new Sk.builtin.func((k) => toPy(iskeydown(k ? toJS(k) : undefined))); + mod.iskeypressed = new Sk.builtin.func((k) => toPy(iskeypressed(k ? toJS(k) : undefined))); + mod.rand = new Sk.builtin.func((mn, mx) => toPy(rand(mn ? toJS(mn) : 0, mx ? toJS(mx) : 1))); + mod.randi = new Sk.builtin.func((mn, mx) => toPy(randi(mn ? toJS(mn) : 0, mx ? toJS(mx) : 1))); + mod.sin = new Sk.builtin.func((a) => toPy(Math.sin(toJS(a)))); + mod.cos = new Sk.builtin.func((a) => toPy(Math.cos(toJS(a)))); + mod.abs = new Sk.builtin.func((n) => toPy(Math.abs(toJS(n)))); + mod.sqrt = new Sk.builtin.func((n) => toPy(Math.sqrt(toJS(n)))); + mod.pause = new Sk.builtin.func(() => { pause(); return Sk.builtin.none.none$; }); + mod.resume = new Sk.builtin.func(() => { resume(); return Sk.builtin.none.none$; }); + + return mod; +}; \ No newline at end of file