1
1
Fork 0
mirror of https://github.com/boxgaming/qbjs.git synced 2024-04-28 17:20:13 +00:00

v0.3.0-beta updates

This commit is contained in:
boxgaming 2022-03-30 17:37:36 -05:00
parent 03466d5c32
commit 137145cc85
11 changed files with 1402 additions and 1548 deletions

View file

@ -35,13 +35,18 @@ CodeMirror.defineMode("qbjs", function(conf, parserConf) {
// TODO: adjust for QB
var atomWords = ['true', 'false', 'nothing', 'empty', 'null'];
var builtinFuncsWords = ['_alpha', '_alpha32', '_atan2', '_autodisplay', '_blue', '_blue32', '_copyimage', '_delay', '_dest', '_dest', '_display', '_fontwidth',
'_freeimage', '_green', '_green32', '_height', '_instrrev', '_limit', '_keyclear', '_keydown', '_keyhit', '_loadimage',
'_mousebutton', '_mouseinput', '_mousex', '_mousey', '_newimage', '_pi', '_printstring', '_printwidth', '_putimage',
'_red', '_red32', '_rgb', '_rgba', '_rgb32', '_rgba32', '_round', '_screenexists', '_title', '_trim', '_width', 'abs',
'asc', 'atn', 'chr', 'circle', 'cls', 'color', 'command', 'cos', 'exp', 'fix', 'input', 'inkey', 'instr', 'int',
'lbound', 'left', 'lcase', 'len', 'line', 'locate', 'log', 'ltrim', 'mid', 'print', 'pset', 'right', 'rtrim', 'rnd',
'screen', 'sgn', 'sin', 'sleep', 'sqr', 'str', 'swap', 'tan', 'timer', 'ubound', 'ucase', 'val'];
var builtinFuncsWords = ['_alpha', '_alpha32', '_atan2', '_autodisplay', '_blue', '_blue32', '_continue', '_copyimage', '_delay', '_dest', '_dest',
'_display', '_fontwidth', '_freeimage', '_green', '_green32', '_height', '_instrrev', '_limit', '_keyclear', '_keydown',
'_keyhit', '_loadimage', '_mousebutton', '_mouseinput', '_mousex', '_mousey', '_newimage', '_pi', '_printstring', '_printwidth',
'_putimage', '_red', '_red32', '_resize', '_resizewidth', '_resizeheight', '_rgb', '_rgba', '_rgb32', '_rgba32', '_round',
'_screenexists', '_sndclose', '_sndopen', '_sndplay', '_sndloop', '_sndpause', '_sndstop', '_sndvol',
'_title', '_trim', '_width', 'abs', 'asc', 'atn', 'chr', 'circle', 'cls', 'color', 'command', 'cos', 'cvi', 'cvl', 'exp',
'fix', 'input', 'inkey', 'instr', 'int', 'lbound', 'left', 'lcase', 'len', 'line', 'locate', 'log', 'ltrim', 'mid', 'mki', 'mkl',
'print', 'pset', 'right', 'rtrim', 'rnd', 'screen', 'shared', 'sgn', 'sin', 'sleep', 'space', 'sqr', 'str', 'swap', 'tan',
'timer', 'ubound', 'ucase', 'val',
// QBJS-specific
'alert', 'confirm', 'domadd', 'domcontainer', 'domcreate', 'domevent','domget', 'domgetimage', 'domremove', 'prompt',
'storageclear', 'storageget', 'storagekey', 'storagelength', 'storageset', 'storageremove'];
var builtinConsts = ['gx_true', 'gx_false', 'gxevent_init', 'gxevent_update', 'gxevent_drawbg', 'gxevent_drawmap', 'gxevent_drawscreen',
'gxevent_mouseinput', 'gxevent_paintbefore', 'gxevent_paintafter', 'gxevent_collision_tile', 'gxevent_collision_entity',
@ -64,7 +69,8 @@ CodeMirror.defineMode("qbjs", function(conf, parserConf) {
'gxscene_follow_entity_center_x', 'gxscene_follow_entity_center_y', 'gxscene_follow_entity_center_x_pos',
'gxscene_follow_entity_center_x_neg', 'gxscene_constrain_none', 'gxscene_constrain_to_map', 'gxfont_default',
'gxfont_default_black', 'gxdevice_keyboard', 'gxdevice_mouse', 'gxdevice_controller', 'gxdevice_button',
'gxdevice_axis', 'gxdevice_wheel', 'gxtype_entity', 'gxtype_font', 'gx_cr', 'gx_lf', 'gx_crlf'];
'gxdevice_axis', 'gxdevice_wheel', 'gxtype_entity', 'gxtype_font', 'gx_cr', 'gx_lf', 'gx_crlf',
'local', 'session'];
var builtinObjsWords = ['\\$if', '\\$end if'];

View file

@ -1,105 +0,0 @@
'use strict';
/**
* Polyfill of dialog
* for Firefox
*
* author Nemo
*
* v1.1
* Supports:
* show
* hide
* showModal
* cancel(ESC)
*/
{
const UA = window.navigator.userAgent;
const browser = {
isFirefox: UA.includes('Firefox'),
};
const dlg = document.createElement('dialog');
let mask = undefined;
const initMask = () => {
if (mask != undefined)
return;
mask = document.createElement('div');
mask.style.display = 'none';
mask.style.position = 'absolute';
mask.style.zIndex = 999998;
mask.style.top = 0;
mask.style.left = 0;
mask.style.right = 0;
mask.style.bottom = 0;
mask.style.backgroundColor = 'rgba(0, 0, 0, 0.1)';
document.body.appendChild(mask);
};
// show support
if (!dlg.__proto__.show) {
dlg.__proto__.open = false;
dlg.__proto__.show = function() {
this.open = true;
this.style.backgroundColor = 'white';
this.style.position = 'absolute';
this.style.zIndex = 999999;
this.style.display = 'table';
this.style.top = '50%';
this.style.transform = 'translate(0, -50%)';
return this;
};
}
// showModal support
if (!dlg.__proto__.showModal) {
initMask();
dlg.__proto__.showModal = function() {
mask.style.display = 'block';
this.show();
return this;
};
}
// hide support
if (!dlg.__proto__.close) {
initMask();
dlg.__proto__.close = function() {
this.open = false;
mask.style.display = 'none';
this.style.display = 'none';
return this;
}
}
// cancel(ESC) support
if (dlg.oncancel === void 0) {
const dialogClass = 'dlg-dialog';
document.addEventListener('keypress', (e) => {
if (e.code !== 'Escape')
return;
let dlgs = document.querySelectorAll(`.${dialogClass}`);
for (let i = 0; i < dlgs.length; i++) {
let d = dlgs[i];
if (d.style.display === 'none')
continue;
if (d.wrapper.cancelable) {
d.close();
}
}
});
}
}

View file

@ -1,18 +0,0 @@
.dlg-dialog {
border: none;
box-shadow: 10px 10px 20px gray;
}
.dlg-header {
background-color: #555;
color: white;
}
.dlg-caption {
height: 1.17em;
text-shadow: 1px 1px 1px black;
}
.dlg-close-button::before,
.dlg-close-button::after {
background-color: white;
}

View file

@ -1,81 +0,0 @@
.dlg-dialog {
position: fixed;
top: 0;
bottom: 0;
box-sizing: border-box;
min-width: 300px;
max-width: 100%;
padding: 0;
overflow: hidden;
background-color: #ccc;
}
.dlg-dialog textarea {
background-color: #ccc;
font-family: dosvga;
font-size: 1em;
padding: .25em;
border: 2px solid #333;
}
.dlg-header {
padding: .5em;
background-color: #999;
border-bottom: 1px solid #333;
}
.dlg-caption {
font-size: 1em;
margin: 0;
padding-right: 2em;
font-weight: normal;
}
.dlg-close-button {
position: absolute;
right: .5em;
top: .5em;
width: 1.17em;
height: 1.17em;
cursor: pointer;
}
.dlg-close-button::before {
transform: rotate(45deg);
}
.dlg-close-button::after{
transform: rotate(-45deg);
}
.dlg-close-button::before,
.dlg-close-button::after {
content: '';
position: absolute;
height: 1px;
width: 100%;
top: 50%;
left:0;
background-color: black;
}
.dlg-body {
padding: .5em;
}
.dlg-content {
padding: .5em;
overflow: auto;
}
.dlg-button-area {
padding: 0 .5em;
text-align: right;
}
.dlg-button-area button {
padding: .3em .4em;
margin-left: 1em;
width: 5em;
text-align: center;
}

View file

@ -1,435 +0,0 @@
/**
* class Dialog {
*
* author: nemo
* date: 2017-06-20
* v: 1.1
* }
*/
{
'use strict';
class Dialog {
constructor(opt) {
Object.assign(this.option = {
caption: '',
message: '',
content: undefined,
buttons: Dialog.buttons.NONE,
resize: 'none',
cancelable: true,
showHeader: true,
showClose: true,
showFooter: false,
// handler
abortHandler: undefined,
cancelHandler: () => { this.close(); },
ignoreHandler: undefined,
noHandler: undefined,
okHandler: () => { this.close(); },
retryHandler: undefined,
yesHandler: undefined,
// events
beforeClosing: () => { return true; }, // set to false to prevent close
closed: undefined,
}, opt);
this.init();
}
/**
* START init
*/
init() {
return this
.initLayout()
.initAttributes()
.initContent()
.initEvents();
}
initLayout() {
this.dialog = create('dialog', 'dialog');
this.dialog.style.resize = this.option.resize,
appendTo(this.dialog, document.body);
this.show();
this.container = this.dialog;
this.header = create('header', 'header');
this.caption = create('h3', 'caption');
this.closeButton = create('em', 'close-button');
this.body = create('div', 'body');
this.content = create('section', 'content');
this.buttonArea = create('div', 'button-area');
this.footer = create('footer', 'footer');
// assembly dom
this.header.appendChild(this.caption);
if (this.option.showClose)
this.header.appendChild(this.closeButton);
if (this.option.showHeader)
this.dialog.appendChild(this.header);
this.body.appendChild(this.content);
this.body.appendChild(this.buttonArea);
this.assemblyButtons();
this.dialog.appendChild(this.body);
if (this.option.showFooter)
this.dialog.appendChild(this.footer);
return this;
}
initAttributes() {
this.dialog.wrapper = this;
this.cancelable = this.option.cancelable;
return this;
}
assemblyButtons() {
switch (this.option.buttons) {
case Dialog.buttons.ABORT_RETRY_IGNORE:
new DialogButton(this, Dialog.button.ABORT).assembly();
new DialogButton(this, Dialog.button.RETRY).assembly().focus();
new DialogButton(this, Dialog.button.IGNORE).assembly();
break;
case Dialog.buttons.OK:
new DialogButton(this, Dialog.button.OK).assembly().focus();
break;
case Dialog.buttons.OK_CANCEL:
new DialogButton(this, Dialog.button.OK).assembly();
new DialogButton(this, Dialog.button.CANCEL).assembly().focus();
break;
case Dialog.buttons.RETRY_CANCEL:
new DialogButton(this, Dialog.button.RETRY).assembly().focus();
new DialogButton(this, Dialog.button.CANCEL).assembly();
break;
case Dialog.buttons.YES_NO:
new DialogButton(this, Dialog.button.YES).assembly();
new DialogButton(this, Dialog.button.NO).assembly().focus();
break;
case Dialog.buttons.YES_NO_CANCEL:
new DialogButton(this, Dialog.button.YES).assembly();
new DialogButton(this, Dialog.button.NO).assembly();
new DialogButton(this, Dialog.button.CANCEL).assembly().focus();
break;
default:
// no button
break;
}
return this;
}
appendButton(btn) {
this.buttonArea.appendChild(btn.button);
return this;
}
removeButton(btn) {
this.buttonArea.removeChild(btn.button);
return this;
}
initContent() {
this.caption.innerText = this.option.caption;
if (this.option.content == undefined) {
this.content.innerText = this.option.message;
} else {
this.content.innerHTML = this.option.content;
}
return this;
}
initEvents() {
this.closeButton.addEventListener('click', () => {
this.close();
});
// prevent esc
this.dialog.addEventListener('cancel', (e) => {
!this.cancelable && e.preventDefault();
});
return this;
}
/**
* END init
*/
//:~
trigger(type) {
switch (type) {
case Dialog.button.ABORT:
callHandler(this.option.abortHandler, this);
break;
case Dialog.button.CANCEL:
callHandler(this.option.cancelHandler, this);
break;
case Dialog.button.IGNORE:
callHandler(this.option.ignoreHandler, this);
break;
case Dialog.button.NO:
callHandler(this.option.noHandler, this);
break;
case Dialog.button.OK:
callHandler(this.option.okHandler, this);
break;
case Dialog.button.RETRY:
callHandler(this.option.retryHandler, this);
break;
case Dialog.button.YES:
callHandler(this.option.yesHandler, this);
break;
default:
console.log(`Unknown type:${type}`);
break;
}
return this;
}
beforeClosing(func) {
this.option.beforeClosing = func;
return this;
}
closed(func) {
this.dialog.addEventListener('close', func);
return this;
}
get cancelable() {
return this.option.cancelable;
}
set cancelable(value) {
this.option.cancelable = !!value;
}
show() {
if (this.dialog.open)
return this;
try {
this.dialog.showModal();
} catch (e) {
appendTo(this.dialog, document.body);
this.dialog.showModal();
}
return this;
}
hide(dispose = true) {
if (!this.dialog.open)
return this;
if (typeof this.option.beforeClosing != 'function' ||
!!this.option.beforeClosing()) {
this.dialog.close();
try {
dispose && document.body.removeChild(this.dialog);
} finally { }
}
return this;
}
close(dispose = true) {
return this.hide(dispose);
}
addClass(className) {
addClass(this.dialog, className);
}
//:~
/**
* START static helper
*/
static alert(message, caption = '') {
return new Dialog({
caption: `${caption}`,
message: `${message}`,
buttons: Dialog.buttons.OK,
});
}
static confirm(message, caption = '', ok, cancel) {
return new Dialog({
caption: `${caption}`,
message: `${message}`,
buttons: Dialog.buttons.OK_CANCEL,
okHandler: ok,
cancelHandler: cancel,
});
}
static template(dom, caption = '') {
return new Dialog({
caption: `${caption}`,
content: dom.innerHTML,
});
}
static templet(dom, caption) {
return template(dom, caption);
}
static iframe(src, caption = '', width = 'auto', height = 'auto') {
let dlg = new Dialog({
caption: `${caption}`,
content: `<iframe style="border: none;" src="${src}"></iframe>`,
});
let iframe = dlg.content.childNodes[0];
iframe.style.width = width;
iframe.style.height = height;
}
/**
* END static helper
*/
}
class DialogButton {
constructor(dialog, type) {
this.dialog = dialog;
this.type = type;
this.button = create('button', `btn-${type}`);
this.button.type = 'button';
this.button.innerText = Dialog.buttonText[type];
this.click(() => {
this.dialog.trigger(this.type);
});
}
assembly() {
this.dialog.appendButton(this);
return this;
}
click(func) {
this.button.addEventListener('click', func);
return this;
}
focus() {
window.setTimeout(() => {
this.button.focus();
}, 1);
return this;
}
}
Object.assign(Dialog, {
buttons: {
ABORT_RETRY_IGNORE: 1,
OK: 2,
OK_CANCEL: 3,
RETRY_CANCEL: 4,
YES_NO: 5,
YES_NO_CANCEL: 6,
},
button: {
NONE: 0,
ABORT: 1,
CANCEL: 2,
IGNORE: 3,
NO: 4,
OK: 5,
RETRY: 6,
YES: 7,
},
buttonText: [
undefined,
'Abort',
'Cancel',
'Ignore',
'NO',
'OK',
'Retry',
'Yes',
],
});
let callHandler = (func, dlg) => {
return typeof func == 'function' ?
func(dlg) : undefined;
}
let cls = (cls) => {
return `dlg-${cls}`;
}
let addClass = (dom, className) => {
let c = dom.className;
let add = cls(className);
if (c == '') {
return add;
} else {
return c + ' ' + add;
}
}
let prependTo = (sub, base) => {
if (base.hasChildNodes()) {
base.insertBefore(sub, base.firstChild);
} else {
base.appendChild(sub);
}
}
let appendTo = (sub, base) => {
base.appendChild(sub);
}
let show = (dom, display = 'block') => {
visible(dom, true, display);
}
let hide = (dom) => {
visible(dom, true);
}
let visible = (dom, v, display) => {
if (dom == undefined || dom.style == undefined)
return;
else
dom.style.display = v ? display : 'none';
}
let create = (name, className) => {
let e = document.createElement(name);
if (typeof className == 'string')
e.className = cls(className);
return e;
}
// export { Dialog } // ES6
window['Dialog'] = Dialog;
}

View file

@ -572,6 +572,11 @@ var GX = new function() {
// Sound Methods
// ----------------------------------------------------------------------------
function _soundClose (sid) {
_sounds[sid-1].pause();
_sounds[sid-1] = undefined;
}
function _soundLoad (filename) {
var a = new Audio(filename);
_sounds.push(a);
@ -613,7 +618,6 @@ var GX = new function() {
return _sound_muted;
}
// Entity Functions
// -----------------------------------------------------------------------------
function _entityCreate (imageFilename, ewidth, height, seqFrames, uid) {
@ -2299,6 +2303,7 @@ var GX = new function() {
this.backgroundHeight = _backgroundHeight;
this.backgroundClear = _backgroundClear;
this.soundClose = _soundClose;
this.soundLoad = _soundLoad;
this.soundPlay = _soundPlay;
this.soundRepeat = _soundRepeat;

View file

@ -116,16 +116,60 @@
background-color: transparent;
color: #ccc;
}
#gx-load-screen {
display: none;
text-align: center;
margin: auto;
width: 600px;
height: 360px;
font-size: 24px;
color: #ccc;
border: 1px solid #000;
text-decoration: none;
background-position: center center;
background-image: url('play.png');
background-repeat: no-repeat;
background-color: #444;
}
#gx-load-screen:hover {
background-color: #555;
}
#gx-load-screen:before { content: ""; }
#gx-load-screen:after { content: ""; }
#gx-container a, #gx-container a:link, #gx-container a:visited {
color: rgb(69, 118, 147);
}
#gx-container a:hover {
color: rgb(69, 118, 147);
text-decoration: underline;
}
#gx-container a:before { content: ""; }
#gx-container a:after { content: ""; }
#gx-container, #gx-container table {
font-family: arial, helvetica, sans-serif;
font-size: 14px;
}
#share-dialog {
background-color:#ddd;
}
#share-dialog textarea {
font-family: dosvga;
font-size: 1em;
background-color: #efefef;
}
#share-dialog a { color: #333; }
#share-dialog a:hover { color: #000; }
</style>
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/codemirror/5.52.2/codemirror.min.css"></link>
<link rel="stylesheet" href="codemirror/qb-ide.css"></link>
<link rel="stylesheet" href="dialog/dialog.css"></link>
<script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/codemirror/5.52.2/codemirror.min.js"></script>
<script type="text/javascript" src="codemirror/qb-lang.js"></script>
<script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/codemirror/5.52.2/addon/selection/active-line.js"></script>
<script type="text/javascript" src="util/shorty.min.js"></script>
<script type="text/javascript" src="dialog/dialog.js"></script>
<script type="text/javascript" src="dialog/dialog-polyfill.js"></script>
</head>
<body>
<div id="code-container">
@ -139,7 +183,9 @@
<div id="slider-right" class="slider-button" onclick="slideRight()">&gt;</div>
</div>
<div id="game-container">
<div id="gx-container"></div>
<div id="gx-container">
<a href="javascript:runProgram()" id="gx-load-screen">&nbsp;</a>
</div>
<div id="output-container">
<div id="tabs">
<div id="tab-console" class="tab active" onclick="changeTab('console')">Console</div><div id="tab-js" class="tab" onclick="changeTab('js')">Javascript</div>
@ -153,9 +199,19 @@
</div>
<div id="gx-footer"></div>
<div style="display:none" id="share-dialog">
<textarea id="share-code" rows="15" cols="80" readonly></textarea>
</div>
<dialog id="share-dialog">
<div style="margin-bottom:5px">Copy the link below to share your code:</div>
<div><textarea id="share-code" rows="15" cols="80" readonly></textarea></div>
<div style="margin-top: 5px; float:left">Launch Mode:
<select id="share-mode" onchange="shareProgram()">
<option value="">IDE (Default)</option>
<option value="play">Play</option>
<option value="auto">Auto</option>
</select>
</div>
<a href="javascript:closeDialog()" style="display:block; float:right; margin-top: 5px">Close</a>
<a href="javascript:testShare()" style="display: block; float:right; margin-top: 5px; margin-right: 10px">Test</a>
</dialog>
</body>
<script language="javascript" src="gx/gx.js"></script>
<script language="javascript" src="qb.js"></script>
@ -166,6 +222,7 @@
var qbcode = "";
var url = location.href;
var sizeMode = "normal";
var appMode = "ide";
var consoleVisible = false;
var currTab = "console";
@ -179,8 +236,14 @@
qbcode = zin.inflate(atob(nv[1]));
break;
}
else if (nv[0] == "mode") {
appMode = nv[1];
}
}
}
if (appMode == "play") {
document.getElementById("gx-load-screen").style.display = "block";
}
// initialize the code editor
var editor = CodeMirror(document.querySelector("#code"), {
@ -209,6 +272,8 @@
var warnCount = 0;
async function runProgram() {
document.getElementById("gx-load-screen").style.display = "none";
if (sizeMode == "max") {
slideLeft();
}
@ -219,7 +284,6 @@
var jsCode = await QBCompiler.compile(qbCode);
await displayWarnings();
//displayTypes();
var jsDiv = document.getElementById("js-code");
jsDiv.innerHTML = jsCode;
@ -244,6 +308,8 @@
GX.sceneStop();
}
document.getElementById("gx-container").focus();
return false;
}
function stopProgram() {
@ -256,9 +322,26 @@
var b64 = btoa(zout.deflate(editor.getValue()));
var baseUrl = location.href.split('?')[0];
var mode = document.getElementById("share-mode").value;
var codeShare = document.getElementById("share-code");
codeShare.innerHTML = baseUrl + "?qbcode=" + b64;
Dialog.template(document.getElementById("share-dialog"), "Copy the link below to share your code!");
var url = baseUrl + "?";
if (mode) {
url += "mode=" + mode + "&";
}
url += "qbcode=" + b64;
codeShare.value = url;
document.getElementById("share-dialog").showModal();
codeShare.focus();
codeShare.select();
}
function testShare() {
var url = document.getElementById("share-code").value;
open(url, "_blank");
}
function closeDialog() {
document.getElementById("share-dialog").close();
}
async function displayWarnings() {
@ -277,7 +360,8 @@
function showConsole() {
consoleVisible = !consoleVisible;
window.onresize();
window.dispatchEvent(new Event('resize'));
//window.onresize();
}
function changeTab(tabName) {
@ -315,7 +399,8 @@
sizeMode = "min"
document.getElementById("slider-left").style.display = "none";
}
window.onresize();
//window.onresize();
window.dispatchEvent(new Event('resize'));
}
function slideRight() {
@ -327,65 +412,81 @@
sizeMode = "max"
document.getElementById("slider-right").style.display = "none";
}
window.onresize();
//window.onresize();
window.dispatchEvent(new Event('resize'));
}
window.onresize = function() {
var f = document.getElementById("gx-container");
var jsDiv = document.getElementById("output-container");
var cmwidth = 600;
if (sizeMode == "min") {
cmwidth = 0;
editor.getWrapperElement().style.display = "none";
document.getElementById("code").style.borderRight = "0";
}
else if (sizeMode == "max") {
cmwidth = window.innerWidth - 25;
document.getElementById("game-container").style.display = "none";
document.getElementById("slider").style.border = "1px solid #666";
document.getElementById("slider").style.borderLeft = "0";
if (appMode == "play" || appMode == "auto") {
f.style.left = "0px";
f.style.top = "0px";
f.style.width = window.innerWidth;
f.style.height = window.innerHeight;
f.style.border = "0px";
document.getElementById("code-container").style.display = "none";
document.getElementById("slider").style.display = "none";
document.getElementById("show-js-container").style.display = "none";
document.getElementById("game-container").style.left = "0px";
document.getElementById("game-container").style.top = "0px";
jsDiv.style.display = "none";
}
else {
editor.getWrapperElement().style.display = "block";
document.getElementById("game-container").style.display = "block";
document.getElementById("code").style.borderRight = "1px solid #666";
document.getElementById("slider").style.border = "0";
}
document.getElementById("game-container").style.left = (cmwidth + 20) + "px";
f.style.width = (window.innerWidth - (cmwidth + 35)) + "px";
jsDiv.style.width = f.style.width;
document.getElementById("slider").style.left = (cmwidth + 12) + "px";
if (consoleVisible) { // /*document.getElementById("show-js").checked ||*/ warnCount > 0) {
f.style.height = (window.innerHeight - 237) + "px";
jsDiv.style.display = "block";
jsDiv.style.top = (window.innerHeight - 227) + "px";
document.getElementById("toggle-console").innerHTML = "Hide Console";
if (currTab == "console") {
document.getElementById("warning-container").style.display = "block";
document.getElementById("js-code").style.display = "none";
var cmwidth = 600;
if (sizeMode == "min") {
cmwidth = 0;
editor.getWrapperElement().style.display = "none";
document.getElementById("code").style.borderRight = "0";
}
else if (sizeMode == "max") {
cmwidth = window.innerWidth - 25;
document.getElementById("game-container").style.display = "none";
document.getElementById("slider").style.border = "1px solid #666";
document.getElementById("slider").style.borderLeft = "0";
}
else {
document.getElementById("warning-container").style.display = "none";
document.getElementById("js-code").style.display = "block";
editor.getWrapperElement().style.display = "block";
document.getElementById("game-container").style.display = "block";
document.getElementById("code").style.borderRight = "1px solid #666";
document.getElementById("slider").style.border = "0";
}
}
else {
f.style.height = (window.innerHeight - 50) + "px";
jsDiv.style.display = "none";
document.getElementById("toggle-console").innerHTML = "Show Console";
}
document.getElementById("show-js-container").style.top = (window.innerHeight - 45) + "px";
document.getElementById("show-js-container").style.right = "5px";
//document.getElementById("js-code").style.display = document.getElementById("show-js").checked ? "block" : "none";
editor.setSize(cmwidth, window.innerHeight - 50);
document.getElementById("code").style.height = (window.innerHeight - 50) + "px";
document.getElementById("slider").style.height = (window.innerHeight - 50) + "px";
document.getElementById("game-container").style.left = (cmwidth + 20) + "px";
f.style.width = (window.innerWidth - (cmwidth + 35)) + "px";
jsDiv.style.width = f.style.width;
document.getElementById("slider").style.left = (cmwidth + 12) + "px";
if (consoleVisible) {
f.style.height = (window.innerHeight - 237) + "px";
jsDiv.style.display = "block";
jsDiv.style.top = (window.innerHeight - 227) + "px";
document.getElementById("toggle-console").innerHTML = "Hide Console";
if (currTab == "console") {
document.getElementById("warning-container").style.display = "block";
document.getElementById("js-code").style.display = "none";
}
else {
document.getElementById("warning-container").style.display = "none";
document.getElementById("js-code").style.display = "block";
}
}
else {
f.style.height = (window.innerHeight - 50) + "px";
jsDiv.style.display = "none";
document.getElementById("toggle-console").innerHTML = "Show Console";
}
document.getElementById("show-js-container").style.top = (window.innerHeight - 45) + "px";
document.getElementById("show-js-container").style.right = "5px";
editor.setSize(cmwidth, window.innerHeight - 50);
document.getElementById("code").style.height = (window.innerHeight - 50) + "px";
document.getElementById("slider").style.height = (window.innerHeight - 50) + "px";
}
//QB.resize(f.style.width.replace("px", ""), f.style.height.replace("px", ""));
QB.resize(f.clientWidth, f.clientHeight);
}
window.onresize();
@ -401,6 +502,10 @@
setTimeout(checkButtonState, 100);
}
checkButtonState();
if (appMode == "auto") {
runProgram();
}
</script>
</html>

BIN
play.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 533 B

251
qb.js
View file

@ -2,6 +2,9 @@ var QB = new function() {
// QB constants
this.COLUMN_ADVANCE = Symbol("COLUMN_ADVANCE");
this.PREVENT_NEWLINE = Symbol("PREVENT_NEWLINE");
this.LOCAL = Symbol("LOCAL");
this.SESSION = Symbol("SESSION");
var _fgColor = null;
var _bgColor = null;
@ -21,7 +24,12 @@ var QB = new function() {
var _images = {};
var _activeImage = 0;
var _nextImageId = 1000;
var _lastLimitTime = 0;
//var _lastLimitTime = 0;
var _resize = false;
var _resizeWidth = 0;
var _resizeHeight = 0;
var _domElements = [];
var _domEvents = [];
// Array handling methods
// ----------------------------------------------------
@ -75,12 +83,19 @@ var QB = new function() {
return value;
};
this.import = async function(url) {
this.resize = function(width, height) {
_resize = true;
_resizeWidth = width;
_resizeHeight = height;
}
/*this.import = async function(url) {
await fetch(url).then(response => response.text()).then((response) => {
var f = new Function(response);
f();
});
};
};*/
// Process control methods
// -------------------------------------------
@ -102,6 +117,7 @@ var QB = new function() {
_haltedFlag = false;
_nextImageId = 1000;
_activeImage = 0;
_domInit();
}
this.running = function() {
@ -177,7 +193,7 @@ var QB = new function() {
return 8;
};
this.func__FreeImage = function(imageId) {
this.sub__FreeImage = function(imageId) {
_images[imageId] = undefined;
}
@ -269,7 +285,7 @@ var QB = new function() {
this.func__NewImage = function(iwidth, iheight) {
var canvas = document.createElement("canvas");
canvas.id = "gx-canvas";
canvas.id = "qb-canvas-" + _nextImageId;
canvas.width = iwidth;
canvas.height = iheight;
ctx = canvas.getContext("2d");
@ -398,6 +414,20 @@ var QB = new function() {
return _color(rgb).r;
};
this.func__Resize = function() {
var tmp = _resize;
_resize = false;
return tmp ? -1 : 0;
}
this.func__ResizeHeight = function() {
return _resizeHeight;
};
this.func__ResizeWidth = function() {
return _resizeWidth;
};
this.func__RGB = function(r, g, b) {
return this.func__RGBA(r, g, b);
};
@ -441,7 +471,36 @@ var QB = new function() {
this.func__ScreenExists = function() {
return true;
}
};
this.sub__SndClose = function(sid) {
GX.soundClose(sid);
};
this.func__SndOpen = function(filename) {
return GX.soundLoad(filename);
};
this.sub__SndPlay = function(sid) {
GX.soundPlay(sid);
};
this.sub__SndLoop = function(sid) {
GX.soundRepeat(sid);
};
this.sub__SndPause = function(sid) {
GX.soundPause(sid);
};
this.sub__SndStop = function(sid) {
GX.soundStop(sid);
};
this.sub__SndVol = function(sid, v) {
GX.soundVolumne(sid, v);
};
this.sub__Title = function(title) {
document.title = title;
@ -487,11 +546,15 @@ var QB = new function() {
if (bgColor != undefined) {
color = _color(bgColor);
}
// TODO: parameter variants
ctx = _images[_activeImage].ctx;
ctx.beginPath();
ctx.fillStyle = color.rgba();
ctx.fillRect(0, 0, QB.func__Width() , QB.func__Height());
// reset the text position
_locX = 0;
_locY = 0;
};
function _color(c) {
@ -521,6 +584,24 @@ var QB = new function() {
return Math.cos(value);
};
this.func_Cvi = function(numString) {
var result = 0;
numString = numString.split("").reverse().join("");
for (let i=1;i>=0;i--) {
result+=numString.charCodeAt(1-i)<<(8*i);
}
return result;
}
this.func_Cvl = function(numString) {
var result = 0;
numString = numString.split("").reverse().join("");
for (let i=3;i>=0;i--) {
result+=numString.charCodeAt(3-i)<<(8*i);
}
return result;
}
this.func_Exp = function(value) {
return Math.exp(value);
};
@ -749,6 +830,22 @@ var QB = new function() {
}
};
this.func_Mki = function(num) {
var ascii = "";
for (var i=1; i >= 0; i--) {
ascii += String.fromCharCode((num>>(8*i))&255);
}
return ascii.split("").reverse().join("");
};
this.func_Mkl = function(num) {
var ascii = "";
for (var i=3; i >= 0; i--) {
ascii += String.fromCharCode((num>>(8*i))&255);
}
return ascii.split("").reverse().join("");
};
this.sub_Print = async function(args) {
// Print called with no arguments
if (args == undefined || args == null || args.length < 1) {
@ -892,6 +989,7 @@ var QB = new function() {
var img = _images[mode];
if (img && img.canvas) {
GX.sceneCreate(img.canvas.width, img.canvas.height);
this.sub__PutImage(undefined, undefined, undefined, undefined, undefined, undefined, mode);
}
}
_images[0] = { canvas: GX.canvas(), ctx: GX.ctx(), lastX: 0, lastY: 0 };
@ -915,6 +1013,14 @@ var QB = new function() {
else { return 0; }
};
this.func_Space = function(ccount) {
return QB.func_String(ccount, " ");
}
this.func_String = function(ccount, s) {
return "".padStart(ccount, s);
};
this.func_Sin = function(value) {
return Math.sin(value);
};
@ -1000,6 +1106,137 @@ var QB = new function() {
this.func_ToJSON = function(a) {
return JSON.stringify(a);
};
this.sub_Alert = function(text) {
alert(text);
}
this.func_Confirm = function(text) {
return confirm(text) ? -1 : 0;
}
this.sub_DomAdd = function(e, parent, beforeElement) {
if (typeof e == "string") {
e = document.getElementById(e);
}
if (parent == undefined || parent == "") {
parent = QB.func_DomContainer();
}
else if (typeof parent == "string") {
parent = document.getElementById(parent);
}
if (beforeElement == undefined || beforeElement == "") {
beforeElement = null;
}
else if (typeof beforeElement == "string") {
beforeElement = document.getElementById(beforeElement);
}
parent.insertBefore(e, beforeElement);
};
this.func_DomCreate = function(etype, parent, content, eid, beforeElement) {
var e = document.createElement(etype);
if (eid != undefined && eid != "") {
e.id = eid;
}
e.className = "qbjs";
if (content != undefined) {
if (e.value != undefined) {
e.value = content;
}
if (e.innerHTML != undefined) {
e.innerHTML = content;
}
}
_domElements.push(e);
QB.sub_DomAdd(e, parent, beforeElement);
return e;
};
this.sub_DomCreate = function(etype, parent, content, eid, beforeElement) {
this.func_DomCreate(etype, parent, content, eid, beforeElement);
};
this.sub_DomEvent = function(target, eventType, callbackFn) {
if (typeof target == "string") {
target = document.getElementById(target);
}
target.addEventListener(eventType, callbackFn);
_domEvents.push({ target: target, eventType: eventType, callbackFn: callbackFn});
};
this.func_DomContainer = function() {
return document.getElementById("gx-container");
}
this.func_DomGet = function(eid) {
return document.getElementById(eid);
};
this.func_DomGetImage = function(imageId) {
return _images[imageId].canvas;
};
this.sub_DomRemove = function(e) {
if (typeof e == "string") {
e = document.getElementById(e);
}
if (e != undefined && e != null) {
e.remove();
}
}
this.func_Prompt = function(text, defaultValue) {
return prompt(text, defaultValue);
}
function _storage(stype) {
return (stype == QB.SESSION) ? sessionStorage : localStorage;
}
this.sub_StorageClear = function(stype) {
_storage(stype).clear();
}
this.func_StorageGet = function(key, stype) {
return _storage(stype).getItem(key);
}
this.func_StorageKey = function(idx, stype) {
return _storage(stype).key(idx);
}
this.func_StorageLength = function(stype) {
return _storage(stype).length;
}
this.sub_StorageSet = function(key, value, stype) {
_storage(stype).setItem(key, value);
}
this.sub_StorageRemove = function(key, stype) {
_storage(stype).removeItem(key);
}
function _domInit() {
//var elements = document.getElementsByClassName("qbjs");
//for (var i=0; i < elements.length; i++) {
// elements[i].remove();
//}
var e = null;
while (e = _domElements.pop()) {
e.remove();
}
while (e = _domEvents.pop()) {
e.target.removeEventListener(e.eventType, e.callbackFn);
}
}
function _addInkeyPress(e) {

1727
qb2js.js

File diff suppressed because it is too large Load diff

View file

@ -399,7 +399,11 @@ Sub ConvertLines (firstLine As Integer, lastLine As Integer, functionName As Str
If FindMethod(subname, m, "SUB") Then
Dim subargs As String
subargs = Mid$(subline, Len(subname) + 2, Len(subline) - Len(subname) - 2)
If subname = subline Then
subargs = ""
Else
subargs = Mid$(subline, Len(subname) + 2, Len(subline) - Len(subname) - 2)
End If
js = ConvertSub(m, subargs)
Else
AddWarning i, "Missing Sub [" + subname + "], ignoring Call command"
@ -495,7 +499,8 @@ Function ConvertSub$ (m As Method, args As String)
js = CallMethod(m) + "(" + ConvertPutImage(args) + ");"
Else
js = CallMethod(m) + "(" + ConvertExpression(args) + ");"
'js = CallMethod(m) + "(" + ConvertExpression(args) + ");"
js = CallMethod(m) + "(" + ConvertMethodParams(args) + ");"
End If
ConvertSub = js
@ -1147,7 +1152,8 @@ Function ConvertExpression$ (ex As String)
js = js + fneg + "QB.arrayValue(" + bvar.jsname + ", [" + ConvertExpression(ex2) + "]).value"
End If
ElseIf FindMethod(word, m, "FUNCTION") Then
js = js + fneg + "(" + CallMethod(m) + "(" + ConvertExpression(ex2) + "))"
'js = js + fneg + "(" + CallMethod(m) + "(" + ConvertExpression(ex2) + "))"
js = js + fneg + "(" + CallMethod(m) + "(" + ConvertMethodParams(ex2) + "))"
Else
If _Trim$(word) <> "" Then AddWarning i, "Missing function or array [" + word + "]"
' nested condition
@ -1164,6 +1170,24 @@ Function ConvertExpression$ (ex As String)
ConvertExpression = js
End Function
' Handle optional parameters
Function ConvertMethodParams$ (args As String)
Dim js As String
ReDim params(0) As String
Dim argc As Integer
argc = ListSplit(args, params())
Dim i As Integer
For i = 1 To argc
If i > 1 Then js = js + ","
If _Trim$(params(i)) = "" Then
js = js + " undefined"
Else
js = js + " " + ConvertExpression(params(i))
End If
Next i
ConvertMethodParams = js
End Function
Function CallMethod$ (m As Method)
Dim js As String
If m.sync Then js = "await "
@ -1889,6 +1913,15 @@ Sub AddGXConst (vname As String)
AddVariable v, globalVars()
End Sub
Sub AddQBConst (vname As String)
Dim v As Variable
v.type = "CONST"
v.name = vname
v.jsname = "QB." + vname
v.isConst = True
AddVariable v, globalVars()
End Sub
Sub AddGlobal (vname As String, vtype As String, arraySize As Integer)
Dim v As Variable
v.type = vtype
@ -2433,7 +2466,7 @@ Sub InitQBMethods
AddQBMethod "FUNCTION", "_Display", False
AddQBMethod "SUB", "_Display", False
AddQBMethod "FUNCTION", "_FontWidth", False
AddQBMethod "FUNCTION", "_FreeImage", False
AddQBMethod "SUB", "_FreeImage", False
AddQBMethod "FUNCTION", "_Green", False
AddQBMethod "FUNCTION", "_Green32", False
AddQBMethod "FUNCTION", "_Height", False
@ -2454,12 +2487,22 @@ Sub InitQBMethods
AddQBMethod "SUB", "_PutImage", False
AddQBMethod "FUNCTION", "_Red", False
AddQBMethod "FUNCTION", "_Red32", False
AddQBMethod "FUNCTION", "_Resize", False
AddQBMethod "FUNCTION", "_ResizeHeight", False
AddQBMethod "FUNCTION", "_ResizeWidth", False
AddQBMethod "FUNCTION", "_RGB", False
AddQBMethod "FUNCTION", "_RGBA", False
AddQBMethod "FUNCTION", "_RGB32", False
AddQBMethod "FUNCTION", "_RGBA32", False
AddQBMethod "FUNCTION", "_Round", False
AddQBMethod "FUNCTION", "_ScreenExists", False
AddQBMethod "SUB", "_SndClose", False
AddQBMethod "FUNCTION", "_SndOpen", False
AddQBMethod "SUB", "_SndPlay", False
AddQBMethod "SUB", "_SndLoop", False
AddQBMethod "SUB", "_SndPause", False
AddQBMethod "SUB", "_SndStop", False
AddQBMethod "SUB", "_SndVol", False
AddQBMethod "SUB", "_Title", False
AddQBMethod "FUNCTION", "_Trim", False
AddQBMethod "FUNCTION", "_Width", False
@ -2475,6 +2518,8 @@ Sub InitQBMethods
AddQBMethod "SUB", "Color", False
AddQBMethod "FUNCTION", "Command$", False
AddQBMethod "FUNCTION", "Cos", False
AddQBMethod "FUNCTION", "Cvi", False
AddQBMethod "FUNCTION", "Cvl", False
AddQBMethod "FUNCTION", "Exp", False
AddQBMethod "FUNCTION", "Fix", False
AddQBMethod "SUB", "Input", True
@ -2490,6 +2535,8 @@ Sub InitQBMethods
AddQBMethod "FUNCTION", "Log", False
AddQBMethod "FUNCTION", "LTrim$", False
AddQBMethod "FUNCTION", "Mid$", False
AddQBMethod "FUNCTION", "Mki$", False
AddQBMethod "FUNCTION", "Mkl$", False
AddQBMethod "SUB", "Print", True
AddQBMethod "SUB", "PSet", False
AddQBMethod "FUNCTION", "Right$", False
@ -2499,6 +2546,8 @@ Sub InitQBMethods
AddQBMethod "FUNCTION", "Sgn", False
AddQBMethod "FUNCTION", "Sin", False
AddQBMethod "SUB", "Sleep", True
AddQBMethod "FUNCTION", "Space", False
AddQBMethod "FUNCTION", "String", False
AddQBMethod "FUNCTION", "Sqr", False
AddQBMethod "FUNCTION", "Str$", False
AddQBMethod "SUB", "Swap", False
@ -2508,12 +2557,34 @@ Sub InitQBMethods
AddQBMethod "FUNCTION", "UCase$", False
AddQBMethod "FUNCTION", "Val", False
' QBJS-only language features
' --------------------------------------------------------------------------------
AddQBConst "LOCAL"
AddQBConst "SESSION"
AddSystemType "FETCHRESPONSE", "ok:INTEGER,status:INTEGER,statusText:STRING,text:STRING"
AddQBMethod "FUNCTION", "Fetch", True
AddQBMethod "FUNCTION", "FromJSON", False
AddQBMethod "FUNCTION", "ToJSON", False
AddQBMethod "SUB", "Alert", False
AddQBMethod "FUNCTION", "Confirm", False
AddQBMethod "SUB", "DomAdd", False
AddQBMethod "SUB", "DomCreate", False
AddQBMethod "FUNCTION", "DomContainer", False
AddQBMethod "FUNCTION", "DomCreate", False
AddQBMethod "SUB", "DomEvent", False
AddQBMethod "FUNCTION", "DomGet", False
AddQBMethod "FUNCTION", "DomGetImage", False
AddQBMethod "SUB", "DomRemove", False
AddQBMethod "FUNCTION", "Prompt", False
AddQBMethod "SUB", "StorageClear", False
AddQBMethod "FUNCTION", "StorageGet", False
AddQBMethod "FUNCTION", "StorageKey", False
AddQBMethod "FUNCTION", "StorageLength", False
AddQBMethod "SUB", "StorageSet", False
AddQBMethod "SUB", "StorageRemove", False
End Sub
'$include: '../../gx/gx/gx_str.bm'