Redesigned the editor, and added the canvas library
This commit is contained in:
383
editor.html
383
editor.html
@@ -1,124 +1,225 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>Code Editor</title>
|
||||
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/xterm/css/xterm.css" />
|
||||
<script src="https://cdn.jsdelivr.net/npm/xterm/lib/xterm.js"></script>
|
||||
<script src="https://cdn.jsdelivr.net/npm/xterm-addon-fit/lib/xterm-addon-fit.js"></script>
|
||||
<script src="http://skulpt.org/js/skulpt.min.js"></script>
|
||||
<script src="http://skulpt.org/js/skulpt-stdlib.js"></script>
|
||||
<script src="https://unpkg.com/litecanvas/dist/dist.dev.js"></script>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<style>
|
||||
:root {
|
||||
--header-height: 48px;
|
||||
--bg-dark: #1e1e1e;
|
||||
--bg-editor: #272822;
|
||||
/* Monokai background matches ACE default */
|
||||
--bg-canvas: #0e0e0e;
|
||||
--text-color: #f0f0f0;
|
||||
--btn-bg: #f8f8f8;
|
||||
--btn-hover: #e0e0e0;
|
||||
--icon-color: #333;
|
||||
}
|
||||
|
||||
body {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
width: 100vw;
|
||||
height: 100vh;
|
||||
background-color: var(--bg-dark);
|
||||
color: var(--text-color);
|
||||
font-family: 'Inter', 'Segoe UI', Tahoma, sans-serif;
|
||||
display: flex;
|
||||
height: calc(100vh-1.5vw);
|
||||
background-color: #131212;
|
||||
margin: 1.5vw;
|
||||
padding: 0px;
|
||||
/*overflow: hidden;*/
|
||||
}
|
||||
p{
|
||||
color: white;
|
||||
font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
|
||||
margin: 1vw;
|
||||
}
|
||||
.codeEditor{
|
||||
width: 37vw;
|
||||
height: 85vh;
|
||||
border-radius: 10px;
|
||||
overflow: hidden;
|
||||
margin-bottom: 1vw;
|
||||
}
|
||||
.documentationLookup{
|
||||
width: 37vw;
|
||||
height: 7vh;
|
||||
border-radius: 10px;
|
||||
flex-direction: column;
|
||||
overflow: hidden;
|
||||
}
|
||||
.canvas{
|
||||
width: 58vw;
|
||||
/* height: 33.75vw; */
|
||||
aspect-ratio: 16/9;
|
||||
border-radius: 10px;
|
||||
overflow: hidden;
|
||||
margin-bottom: 1vw;
|
||||
|
||||
/* Header */
|
||||
header {
|
||||
height: var(--header-height);
|
||||
background-color: #2c292d;
|
||||
/* Slightly different dark */
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
padding: 0 12px;
|
||||
border-bottom: 1px solid #111;
|
||||
z-index: 100;
|
||||
}
|
||||
#canvas{
|
||||
|
||||
.header-left,
|
||||
.header-right {
|
||||
display: flex;
|
||||
gap: 8px;
|
||||
}
|
||||
|
||||
.label-btn {
|
||||
height: 34px;
|
||||
background-color: #f0f0e6;
|
||||
border: 1px solid #ccc;
|
||||
border-radius: 4px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
cursor: pointer;
|
||||
transition: background 0.2s;
|
||||
padding: 2;
|
||||
}
|
||||
|
||||
.label-btn p {
|
||||
font-size: 16px;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.icon-btn {
|
||||
width: 34px;
|
||||
height: 34px;
|
||||
background-color: #f0f0e6;
|
||||
border: 1px solid #ccc;
|
||||
border-radius: 4px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
cursor: pointer;
|
||||
transition: background 0.2s;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
.icon-btn:hover {
|
||||
background-color: #fff;
|
||||
}
|
||||
|
||||
.icon-btn svg {
|
||||
width: 20px;
|
||||
height: 20px;
|
||||
fill: #222;
|
||||
}
|
||||
|
||||
main {
|
||||
display: flex;
|
||||
flex: 1;
|
||||
height: calc(100vh - var(--header-height));
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
#editor-container {
|
||||
width: 50%;
|
||||
height: 100%;
|
||||
width:100%;
|
||||
background: white;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
background-color: var(--bg-editor);
|
||||
border-right: 2px solid #333;
|
||||
}
|
||||
.terminal{
|
||||
width: 58vw;
|
||||
height: 8vw;
|
||||
border-radius: 10px;
|
||||
overflow: hidden;
|
||||
}
|
||||
#terminal{
|
||||
|
||||
#editor {
|
||||
flex: 1;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
.xterm-screen{
|
||||
padding: 0.75vw;
|
||||
background: #2F3129;
|
||||
overflow: scroll;
|
||||
}
|
||||
.left {
|
||||
|
||||
#preview-container {
|
||||
width: 50%;
|
||||
height: 100%;
|
||||
background-color: var(--bg-canvas);
|
||||
position: relative;
|
||||
display: flex;
|
||||
margin-right: 1vw;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.right {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
|
||||
canvas {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
display: block;
|
||||
}
|
||||
|
||||
.overlay-text {
|
||||
position: absolute;
|
||||
pointer-events: none;
|
||||
color: rgba(255, 255, 255, 0.7);
|
||||
font-family: 'Segoe UI', sans-serif;
|
||||
font-weight: 500;
|
||||
}
|
||||
|
||||
#terminal-container {
|
||||
height: 150px;
|
||||
width: 100%;
|
||||
background-color: #000;
|
||||
border-top: 2px solid #333;
|
||||
overflow: hidden;
|
||||
display: block;
|
||||
}
|
||||
|
||||
#terminal {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
</style>
|
||||
|
||||
<div class="left">
|
||||
<div class="canvas">
|
||||
<canvas id="canvas" style="height: 100%;width:100%;background: white;"></canvas>
|
||||
<header>
|
||||
<div class="header-left">
|
||||
<button class="label-btn" title="PyStudio">
|
||||
<p>PyStudio</p>
|
||||
</button>
|
||||
<button class="icon-btn" title="Run Code" onclick="runCurrentCode()">
|
||||
<svg viewBox="0 0 24 24">
|
||||
<path d="M8 5v14l11-7z" />
|
||||
</svg>
|
||||
</button>
|
||||
<button class="icon-btn" title="Stop Code" onclick="stopCurrentCode()">
|
||||
<svg viewBox="0 0 24 24">
|
||||
<path d="M6 6h12v12H6z" />
|
||||
</svg>
|
||||
</button>
|
||||
</div>
|
||||
<div class="terminal">
|
||||
<div id="terminal"></div>
|
||||
</div>
|
||||
</div>
|
||||
</header>
|
||||
|
||||
<div class="right">
|
||||
|
||||
<div class="codeEditor">
|
||||
<div style="overflow: hidden; height: 3vw;width: 100%;background: #2F3129;">
|
||||
<p style="float: left;">main.py</p>
|
||||
<button onclick="stopCurrentCode()" style="height: 100%; aspect-ratio: 1/1; float: right; border-radius: 0px; border: none;padding: 0.75vw; background: #282923;"><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 448 512"><path fill="#aaa" d="M64 32l320 0c35.3 0 64 28.7 64 64l0 320c0 35.3-28.7 64-64 64L64 480c-35.3 0-64-28.7-64-64L0 96C0 60.7 28.7 32 64 32z"/></svg></button>
|
||||
<button onclick="runCurrentCode()" style="height: 100%; aspect-ratio: 1/1; float: right; border-radius: 0px; border: none;padding: 0.75vw; background: #282923;"><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 448 512"><path fill="#aaa" d="M91.2 36.9c-12.4-6.8-27.4-6.5-39.6 .7S32 57.9 32 72l0 368c0 14.1 7.5 27.2 19.6 34.4s27.2 7.5 39.6 .7l336-184c12.8-7 20.8-20.5 20.8-35.1s-8-28.1-20.8-35.1l-336-184z"/></svg></button>
|
||||
<main>
|
||||
<div id="editor-container">
|
||||
<div id="editor"></div>
|
||||
<div id="terminal-container">
|
||||
<div id="terminal"></div>
|
||||
</div>
|
||||
<div id='editor' style="height: calc(100% - 3vw);width:100%;"></div>
|
||||
</div>
|
||||
|
||||
<div class="documentationLookup">
|
||||
<input type="text" placeholder="Documentation" style="height: 100%;width: 100%;background: #2F3129;border: 0px;color: white;padding-left: 1vw;"></input>
|
||||
<div id="preview-container">
|
||||
<canvas id="canvas"></canvas>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</main>
|
||||
|
||||
<script src="https://www.unpkg.com/ace-builds@latest/src-noconflict/ace.js" crossorigin="anonymous"></script>
|
||||
|
||||
<script>
|
||||
codeEditor = ace.edit("editor", {
|
||||
theme: "ace/theme/monokai",
|
||||
mode: "ace/mode/python",
|
||||
value: "print('Hello world!')"
|
||||
value: "import screen as s\n\ndef draw():\n s.cls(0)\n s.text(20, 20, \"Hello World!\", 3)\n\ns.start({\n \"loop\":{\n \"draw\":draw\n }\n})",
|
||||
fontFamily: 'Consolas, monospace',
|
||||
fontSize: '14px'
|
||||
});
|
||||
|
||||
codeEditor.setShowPrintMargin(false);
|
||||
|
||||
let StopExecution;
|
||||
let term;
|
||||
let inputResolve;
|
||||
let inputBuffer = '';
|
||||
let acceptingInput = false;
|
||||
|
||||
term = new Terminal({ cursorBlink: true });
|
||||
term = new Terminal({
|
||||
cursorBlink: true,
|
||||
theme: {
|
||||
background: '#1e1e1e'
|
||||
}
|
||||
});
|
||||
term.open(document.getElementById('terminal'));
|
||||
term.fit();
|
||||
|
||||
function outf(text) {
|
||||
term.write(text.replace(/\n/g, '\r\n'));
|
||||
@@ -129,67 +230,121 @@
|
||||
inputBuffer = '';
|
||||
inputResolve = resolve;
|
||||
acceptingInput = true;
|
||||
term.write(promptText);
|
||||
console.log("Input requested: " + promptText);
|
||||
});
|
||||
}
|
||||
|
||||
term.onKey(e => {
|
||||
if (!acceptingInput) return;
|
||||
const key = e.key;
|
||||
const ev = e.domEvent;
|
||||
|
||||
if (ev.key === 'Enter') {
|
||||
term.write('\r\n');
|
||||
if (inputResolve) {
|
||||
inputResolve(inputBuffer);
|
||||
inputResolve = null;
|
||||
acceptingInput = false;
|
||||
}
|
||||
} else if (ev.key === 'Backspace') {
|
||||
if (inputBuffer.length > 0) {
|
||||
inputBuffer = inputBuffer.slice(0, -1);
|
||||
term.write('\b \b');
|
||||
}
|
||||
} else if (key.length === 1) {
|
||||
inputBuffer += key;
|
||||
term.write(key);
|
||||
}
|
||||
|
||||
function runCode(code) {
|
||||
term.clear();
|
||||
Sk.configure({
|
||||
output: outf,
|
||||
read: x => Sk.builtinFiles.files[x],
|
||||
inputfun: inputf,
|
||||
inputfunTakesPrompt: true
|
||||
});
|
||||
Sk.misceval.asyncToPromise(() => Sk.importMainWithBody('<stdin>', false, code, true))
|
||||
.catch(err => outf(err.toString() + '\n'));
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
function stopCurrentCode() {
|
||||
StopExecution = true;
|
||||
if (window.__lc_instance) {
|
||||
if (window.__lc_instance.pause) window.__lc_instance.pause();
|
||||
window.__lc_instance = null;
|
||||
}
|
||||
|
||||
const oldCanvas = document.getElementById('canvas');
|
||||
if (oldCanvas) {
|
||||
const newCanvas = oldCanvas.cloneNode(true);
|
||||
oldCanvas.parentNode.replaceChild(newCanvas, oldCanvas);
|
||||
|
||||
const ctx = newCanvas.getContext('2d');
|
||||
if (ctx) {
|
||||
ctx.fillStyle = '#0e0e0e';
|
||||
ctx.fillRect(0, 0, newCanvas.width, newCanvas.height);
|
||||
}
|
||||
}
|
||||
|
||||
const globals = ['W', 'H', 'T', 'MX', 'MY', 'CENTERX', 'CENTERY', 'ENGINE', 'WIDTH', 'HEIGHT'];
|
||||
globals.forEach(g => {
|
||||
delete window[g];
|
||||
window[g] = undefined;
|
||||
});
|
||||
}
|
||||
|
||||
function builtinRead(x) {
|
||||
if (x === 'screen' || x === './screen.js') {
|
||||
const xhr = new XMLHttpRequest();
|
||||
xhr.open("GET", document.location.href + "screen.js", false);
|
||||
xhr.send();
|
||||
if (xhr.status === 200) return xhr.responseText;
|
||||
else throw "Could not load screen.js";
|
||||
}
|
||||
if (Sk.builtinFiles === undefined || Sk.builtinFiles["files"][x] === undefined)
|
||||
|
||||
if (x === 'src/builtin/sys.js') return '';
|
||||
else throw "File not found: '" + x + "'";
|
||||
return Sk.builtinFiles["files"][x];
|
||||
}
|
||||
|
||||
function runCurrentCode() {
|
||||
stopCurrentCode();
|
||||
if (term) term.clear();
|
||||
StopExecution = false;
|
||||
code = codeEditor.getValue();
|
||||
term.clear();
|
||||
var code = codeEditor.getValue();
|
||||
|
||||
const canvas = document.getElementById('canvas');
|
||||
const container = document.getElementById('preview-container');
|
||||
if (canvas && container) {
|
||||
const w = Math.floor(container.clientWidth);
|
||||
const h = Math.floor(container.clientHeight);
|
||||
canvas.width = w;
|
||||
canvas.height = h;
|
||||
}
|
||||
|
||||
Sk.configure({
|
||||
output: outf,
|
||||
read: x => Sk.builtinFiles.files[x],
|
||||
read: builtinRead,
|
||||
inputfun: inputf,
|
||||
inputfunTakesPrompt: true
|
||||
});
|
||||
|
||||
Sk.misceval.asyncToPromise(() => Sk.importMainWithBody('<stdin>', false, code, true), {
|
||||
"*": () => {
|
||||
if (StopExecution) throw "Execution interrupted"
|
||||
}
|
||||
})
|
||||
.catch(err => outf(err.toString() + '\n'));
|
||||
.catch(err => {
|
||||
if (err !== "Execution interrupted") outf(err.toString() + "\n");
|
||||
});
|
||||
}
|
||||
|
||||
function toggleEditor() {
|
||||
runCurrentCode();
|
||||
}
|
||||
|
||||
function takeScreenshot() {
|
||||
const canvas = document.getElementById('canvas');
|
||||
if (canvas) {
|
||||
const link = document.createElement('a');
|
||||
link.download = 'litecanvas-screenshot.png';
|
||||
link.href = canvas.toDataURL();
|
||||
link.click();
|
||||
}
|
||||
}
|
||||
|
||||
document.addEventListener('keydown', function (e) {
|
||||
if ((e.ctrlKey || e.metaKey) && e.key === 'Enter') {
|
||||
e.preventDefault();
|
||||
runCurrentCode();
|
||||
}
|
||||
});
|
||||
|
||||
window.addEventListener('load', () => {
|
||||
setTimeout(runCurrentCode, 100);
|
||||
});
|
||||
|
||||
window.addEventListener('resize', () => {
|
||||
const canvas = document.getElementById('canvas');
|
||||
const container = document.getElementById('preview-container');
|
||||
if (canvas && container) {
|
||||
canvas.width = container.clientWidth;
|
||||
canvas.height = container.clientHeight;
|
||||
}
|
||||
if (term) {
|
||||
term.fit();
|
||||
}
|
||||
});
|
||||
|
||||
</script>
|
||||
</body>
|
||||
|
||||
</html>
|
||||
226
screen.js
Normal file
226
screen.js
Normal file
@@ -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;
|
||||
};
|
||||
Reference in New Issue
Block a user