2017-01-03 15:43:40 +00:00
|
|
|
"use strict";
|
2016-12-16 01:21:51 +00:00
|
|
|
|
2018-07-04 02:14:07 +00:00
|
|
|
// 8bitworkshop IDE user interface
|
2017-01-14 02:31:04 +00:00
|
|
|
|
2018-07-08 03:10:51 +00:00
|
|
|
import $ = require("jquery");
|
|
|
|
import * as bootstrap from "bootstrap";
|
2018-07-08 14:07:19 +00:00
|
|
|
import { CodeProject } from "./project";
|
|
|
|
import { WorkerResult, SourceFile } from "./workertypes";
|
2018-07-08 03:10:51 +00:00
|
|
|
import { ProjectWindows } from "./windows";
|
2018-07-08 04:58:11 +00:00
|
|
|
import { Platform, Preset } from "./baseplatform";
|
2018-07-08 03:10:51 +00:00
|
|
|
import * as Views from "./views";
|
|
|
|
|
|
|
|
// external libs (TODO)
|
|
|
|
declare var Octokat, ga, Tour, GIF, saveAs;
|
|
|
|
declare function createNewPersistentStore(platform_id : string);
|
|
|
|
declare function showLoopTimingForPC(pc:number, sourcefile:SourceFile, wnd:Views.ProjectView);
|
|
|
|
// loaded by platform js file
|
|
|
|
declare var PLATFORMS;
|
2017-01-14 05:47:26 +00:00
|
|
|
|
2018-07-08 03:10:51 +00:00
|
|
|
// make sure VCS doesn't start
|
|
|
|
if (window['Javatari']) window['Javatari'].AUTO_START = false;
|
|
|
|
|
|
|
|
var PRESETS : Preset[]; // presets array
|
|
|
|
var platform_id : string; // platform ID string
|
|
|
|
var platform : Platform; // platform object
|
2017-01-13 02:21:35 +00:00
|
|
|
|
2017-04-12 16:23:24 +00:00
|
|
|
var toolbar = $("#controls_top");
|
|
|
|
|
2018-07-08 03:10:51 +00:00
|
|
|
var current_project : CodeProject; // current CodeProject object
|
2018-06-29 02:42:47 +00:00
|
|
|
|
2018-07-08 03:10:51 +00:00
|
|
|
var projectWindows : ProjectWindows; // window manager
|
2018-07-06 00:13:07 +00:00
|
|
|
|
|
|
|
|
2018-06-29 23:52:09 +00:00
|
|
|
// TODO: codemirror multiplex support?
|
2017-01-16 04:47:12 +00:00
|
|
|
var TOOL_TO_SOURCE_STYLE = {
|
|
|
|
'dasm': '6502',
|
|
|
|
'acme': '6502',
|
|
|
|
'cc65': 'text/x-csrc',
|
|
|
|
'ca65': '6502',
|
|
|
|
'z80asm': 'z80',
|
|
|
|
'sdasz80': 'z80',
|
|
|
|
'sdcc': 'text/x-csrc',
|
2017-11-11 19:45:32 +00:00
|
|
|
'verilator': 'verilog',
|
2018-03-02 05:15:33 +00:00
|
|
|
'jsasm': 'z80'
|
2017-01-16 04:47:12 +00:00
|
|
|
}
|
|
|
|
|
2018-07-08 14:07:19 +00:00
|
|
|
function newWorker() : Worker {
|
2018-06-29 02:42:47 +00:00
|
|
|
return new Worker("./src/worker/workermain.js");
|
|
|
|
}
|
2018-06-28 04:57:06 +00:00
|
|
|
|
2018-07-08 03:10:51 +00:00
|
|
|
var userPaused : boolean; // did user explicitly pause?
|
2018-06-28 04:57:06 +00:00
|
|
|
|
2018-07-08 03:10:51 +00:00
|
|
|
var current_output; // current ROM
|
|
|
|
var current_preset_entry : Preset; // current preset object (if selected)
|
|
|
|
var main_file_id : string; // main file ID
|
2018-07-04 02:14:07 +00:00
|
|
|
var symbolmap; // symbol map
|
|
|
|
var addr2symbol; // address to symbol name map
|
|
|
|
var compparams; // received build params from worker
|
|
|
|
var store; // persistent store
|
2017-01-08 15:51:19 +00:00
|
|
|
|
2018-07-04 02:14:07 +00:00
|
|
|
var lastDebugInfo; // last debug info (CPU text)
|
|
|
|
var lastDebugState; // last debug state (object)
|
2018-07-29 20:26:05 +00:00
|
|
|
var debugCategory; // current debug category
|
2017-04-19 01:18:53 +00:00
|
|
|
|
2018-07-08 14:07:19 +00:00
|
|
|
function inspectVariable(ed, name) { // TODO: ed?
|
2017-11-21 16:15:08 +00:00
|
|
|
var val;
|
|
|
|
if (platform.inspect) {
|
|
|
|
platform.inspect(name);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-07-08 14:07:19 +00:00
|
|
|
function getCurrentPresetTitle() : string {
|
2018-06-28 04:18:16 +00:00
|
|
|
if (!current_preset_entry)
|
2016-12-16 01:21:51 +00:00
|
|
|
return "ROM";
|
|
|
|
else
|
2018-06-28 04:18:16 +00:00
|
|
|
return current_preset_entry.title || current_preset_entry.name || "ROM";
|
2016-12-16 01:21:51 +00:00
|
|
|
}
|
|
|
|
|
2018-07-08 14:07:19 +00:00
|
|
|
function setLastPreset(id:string) {
|
2017-04-29 15:31:11 +00:00
|
|
|
if (platform_id != 'base_z80') { // TODO
|
|
|
|
localStorage.setItem("__lastplatform", platform_id);
|
|
|
|
localStorage.setItem("__lastid_"+platform_id, id);
|
|
|
|
}
|
2016-12-16 01:21:51 +00:00
|
|
|
}
|
|
|
|
|
2018-06-29 23:44:04 +00:00
|
|
|
function initProject() {
|
2018-06-29 02:42:47 +00:00
|
|
|
current_project = new CodeProject(newWorker(), platform_id, platform, store);
|
2018-07-06 00:13:07 +00:00
|
|
|
projectWindows = new ProjectWindows($("#workspace")[0], current_project);
|
|
|
|
current_project.callbackGetRemote = $.get;
|
2018-07-26 13:43:49 +00:00
|
|
|
current_project.callbackBuildResult = (result:WorkerResult) => {
|
|
|
|
setCompileOutput(result);
|
2018-07-02 13:34:20 +00:00
|
|
|
refreshWindowList();
|
2018-06-29 02:42:47 +00:00
|
|
|
};
|
2018-07-25 17:29:09 +00:00
|
|
|
current_project.callbackBuildStatus = (busy:boolean) => {
|
2018-06-29 02:42:47 +00:00
|
|
|
if (busy) {
|
|
|
|
toolbar.addClass("is-busy");
|
|
|
|
} else {
|
|
|
|
toolbar.removeClass("is-busy");
|
2018-06-30 04:42:21 +00:00
|
|
|
toolbar.removeClass("has-errors"); // may be added in next callback
|
2018-07-26 13:43:49 +00:00
|
|
|
projectWindows.setErrors(null);
|
2018-06-29 02:42:47 +00:00
|
|
|
}
|
|
|
|
$('#compile_spinner').css('visibility', busy ? 'visible' : 'hidden');
|
|
|
|
};
|
2018-06-29 23:44:04 +00:00
|
|
|
}
|
2018-06-29 02:42:47 +00:00
|
|
|
|
2018-07-02 13:34:20 +00:00
|
|
|
function refreshWindowList() {
|
|
|
|
var ul = $("#windowMenuList").empty();
|
|
|
|
var separate = false;
|
|
|
|
|
|
|
|
function addWindowItem(id, name, createfn) {
|
|
|
|
if (separate) {
|
|
|
|
ul.append(document.createElement("hr"));
|
|
|
|
separate = false;
|
|
|
|
}
|
|
|
|
var li = document.createElement("li");
|
|
|
|
var a = document.createElement("a");
|
|
|
|
a.setAttribute("class", "dropdown-item");
|
|
|
|
a.setAttribute("href", "#");
|
2018-08-05 14:00:53 +00:00
|
|
|
if (id == projectWindows.getActiveID())
|
|
|
|
$(a).addClass("dropdown-item-checked");
|
2018-07-02 13:34:20 +00:00
|
|
|
a.appendChild(document.createTextNode(name));
|
|
|
|
li.appendChild(a);
|
|
|
|
ul.append(li);
|
|
|
|
if (createfn) {
|
|
|
|
projectWindows.setCreateFunc(id, createfn);
|
2018-07-14 20:10:09 +00:00
|
|
|
$(a).click(function(e) {
|
2018-07-02 13:34:20 +00:00
|
|
|
projectWindows.createOrShow(id);
|
2018-07-14 20:10:09 +00:00
|
|
|
ul.find('a').removeClass("dropdown-item-checked");
|
|
|
|
ul.find(e.target).addClass("dropdown-item-checked");
|
2018-07-02 13:34:20 +00:00
|
|
|
});
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-07-08 14:07:19 +00:00
|
|
|
function loadEditor(path:string) {
|
2018-07-02 13:34:20 +00:00
|
|
|
var tool = platform.getToolForFilename(path);
|
|
|
|
var mode = tool && TOOL_TO_SOURCE_STYLE[tool];
|
2018-07-08 03:10:51 +00:00
|
|
|
return new Views.SourceEditor(path, mode);
|
2018-07-02 13:34:20 +00:00
|
|
|
}
|
2018-07-04 01:09:58 +00:00
|
|
|
|
2018-07-02 13:34:20 +00:00
|
|
|
// add main file editor
|
2018-07-03 03:45:08 +00:00
|
|
|
var id = main_file_id;
|
2018-07-02 13:34:20 +00:00
|
|
|
addWindowItem(id, getFilenameForPath(id), loadEditor);
|
|
|
|
|
2018-07-04 01:09:58 +00:00
|
|
|
// add other source files
|
2018-07-02 13:34:20 +00:00
|
|
|
separate = true;
|
|
|
|
current_project.iterateFiles(function(id, text) {
|
2018-08-06 17:47:55 +00:00
|
|
|
if (text && id != main_file_id)
|
2018-07-02 13:34:20 +00:00
|
|
|
addWindowItem(id, getFilenameForPath(id), loadEditor);
|
|
|
|
});
|
2018-07-04 01:09:58 +00:00
|
|
|
|
|
|
|
// add listings
|
|
|
|
var listings = current_project.getListings();
|
|
|
|
if (listings) {
|
|
|
|
for (var lstfn in listings) {
|
|
|
|
var lst = listings[lstfn];
|
|
|
|
if (lst.assemblyfile) {
|
|
|
|
addWindowItem(lstfn, getFilenameForPath(lstfn), function(path) {
|
2018-07-08 03:10:51 +00:00
|
|
|
return new Views.ListingView(lst.assemblyfile);
|
2018-07-04 01:09:58 +00:00
|
|
|
});
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2018-07-02 13:34:20 +00:00
|
|
|
|
|
|
|
// add other tools
|
|
|
|
separate = true;
|
2018-07-04 01:09:58 +00:00
|
|
|
if (platform.disassemble) {
|
2018-07-02 13:34:20 +00:00
|
|
|
addWindowItem("#disasm", "Disassembly", function() {
|
2018-07-08 03:10:51 +00:00
|
|
|
return new Views.DisassemblerView();
|
2018-07-02 13:34:20 +00:00
|
|
|
});
|
|
|
|
}
|
|
|
|
if (platform.readAddress && platform_id != 'vcs') {
|
|
|
|
addWindowItem("#memory", "Memory Browser", function() {
|
2018-07-08 03:10:51 +00:00
|
|
|
return new Views.MemoryView();
|
2018-07-02 13:34:20 +00:00
|
|
|
});
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-06-28 04:57:06 +00:00
|
|
|
// can pass integer or string id
|
2018-07-08 14:07:19 +00:00
|
|
|
function loadProject(preset_id:string) {
|
2018-06-28 04:57:06 +00:00
|
|
|
var index = parseInt(preset_id+""); // might fail -1
|
2016-12-16 01:21:51 +00:00
|
|
|
for (var i=0; i<PRESETS.length; i++)
|
|
|
|
if (PRESETS[i].id == preset_id)
|
|
|
|
index = i;
|
|
|
|
index = (index + PRESETS.length) % PRESETS.length;
|
|
|
|
if (index >= 0) {
|
|
|
|
// load the preset
|
2018-06-29 23:44:04 +00:00
|
|
|
current_preset_entry = PRESETS[index];
|
|
|
|
preset_id = current_preset_entry.id;
|
2016-12-16 01:21:51 +00:00
|
|
|
}
|
2018-06-29 23:52:09 +00:00
|
|
|
// set current file ID
|
2018-07-03 03:45:08 +00:00
|
|
|
main_file_id = preset_id;
|
2018-07-02 13:34:20 +00:00
|
|
|
setLastPreset(preset_id);
|
2018-07-06 00:13:07 +00:00
|
|
|
current_project.mainPath = preset_id;
|
2018-06-29 23:52:09 +00:00
|
|
|
// load files from storage or web URLs
|
2018-06-29 23:44:04 +00:00
|
|
|
current_project.loadFiles([preset_id], function(err, result) {
|
|
|
|
if (err) {
|
|
|
|
alert(err);
|
|
|
|
} else if (result && result.length) {
|
2018-07-03 03:45:08 +00:00
|
|
|
// we need this to build create functions for the editor (TODO?)
|
2018-07-02 13:34:20 +00:00
|
|
|
refreshWindowList();
|
2018-07-03 03:45:08 +00:00
|
|
|
// show main file
|
2018-08-05 14:00:53 +00:00
|
|
|
projectWindows.createOrShow(preset_id);
|
2018-08-04 14:21:50 +00:00
|
|
|
// build project
|
|
|
|
current_project.setMainFile(preset_id);
|
2018-06-29 23:44:04 +00:00
|
|
|
}
|
|
|
|
});
|
2016-12-16 01:21:51 +00:00
|
|
|
}
|
|
|
|
|
2018-07-08 14:07:19 +00:00
|
|
|
function reloadPresetNamed(id:string) {
|
2017-01-16 15:35:19 +00:00
|
|
|
qs['platform'] = platform_id;
|
|
|
|
qs['file'] = id;
|
2017-01-16 19:13:03 +00:00
|
|
|
gotoNewLocation();
|
2016-12-16 01:21:51 +00:00
|
|
|
}
|
|
|
|
|
2018-07-08 14:07:19 +00:00
|
|
|
function getSkeletonFile(fileid:string, callback) {
|
2018-06-29 23:44:04 +00:00
|
|
|
var ext = platform.getToolForFilename(fileid);
|
|
|
|
$.get( "presets/"+platform_id+"/skeleton."+ext, function( text ) {
|
|
|
|
callback(null, text);
|
|
|
|
}, 'text')
|
|
|
|
.fail(function() {
|
2018-07-02 13:34:20 +00:00
|
|
|
alert("Could not load skeleton for " + platform_id + "/" + ext + "; using blank file");
|
|
|
|
callback(null, '\n');
|
2018-06-29 23:44:04 +00:00
|
|
|
});
|
|
|
|
}
|
|
|
|
|
2016-12-16 01:21:51 +00:00
|
|
|
function _createNewFile(e) {
|
2017-04-23 13:03:05 +00:00
|
|
|
var filename = prompt("Create New File", "newfile" + platform.getDefaultExtension());
|
2016-12-16 01:21:51 +00:00
|
|
|
if (filename && filename.length) {
|
|
|
|
if (filename.indexOf(".") < 0) {
|
2017-04-20 00:55:13 +00:00
|
|
|
filename += platform.getDefaultExtension();
|
2016-12-16 01:21:51 +00:00
|
|
|
}
|
2018-06-29 23:44:04 +00:00
|
|
|
var path = "local/" + filename;
|
|
|
|
getSkeletonFile(path, function(err, result) {
|
|
|
|
if (result) {
|
|
|
|
store.setItem(path, result, function(err, result) {
|
2018-07-02 13:34:20 +00:00
|
|
|
if (err)
|
|
|
|
alert(err+"");
|
|
|
|
if (result != null)
|
2018-06-29 23:52:09 +00:00
|
|
|
reloadPresetNamed("local/" + filename);
|
2018-06-29 23:44:04 +00:00
|
|
|
});
|
|
|
|
}
|
|
|
|
});
|
2016-12-16 01:21:51 +00:00
|
|
|
}
|
2016-12-30 23:51:15 +00:00
|
|
|
return true;
|
2016-12-16 01:21:51 +00:00
|
|
|
}
|
|
|
|
|
2018-06-26 23:57:03 +00:00
|
|
|
function _uploadNewFile(e) {
|
|
|
|
$("#uploadFileElem").click();
|
|
|
|
}
|
|
|
|
|
2018-07-08 14:07:19 +00:00
|
|
|
function handleFileUpload(files: File[]) {
|
2018-06-26 23:57:03 +00:00
|
|
|
console.log(files);
|
|
|
|
var index = 0;
|
|
|
|
function uploadNextFile() {
|
|
|
|
var f = files[index++];
|
|
|
|
if (!f) {
|
|
|
|
console.log("Done uploading");
|
|
|
|
gotoNewLocation();
|
|
|
|
} else {
|
|
|
|
var path = "local/" + f.name;
|
|
|
|
var reader = new FileReader();
|
|
|
|
reader.onload = function(e) {
|
|
|
|
var data = e.target.result;
|
|
|
|
store.setItem(path, data, function(err, result) {
|
|
|
|
if (err)
|
|
|
|
console.log(err);
|
|
|
|
else {
|
|
|
|
console.log("Uploaded " + path + " " + data.length + " bytes");
|
|
|
|
if (index == 1)
|
|
|
|
qs['file'] = path;
|
|
|
|
uploadNextFile();
|
|
|
|
}
|
|
|
|
});
|
|
|
|
}
|
|
|
|
reader.readAsText(f);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (files) uploadNextFile();
|
|
|
|
}
|
|
|
|
|
2018-08-05 14:00:53 +00:00
|
|
|
function getCurrentMainFilename() : string {
|
|
|
|
return getFilenameForPath(main_file_id);
|
|
|
|
}
|
|
|
|
|
|
|
|
function getCurrentEditorFilename() : string {
|
|
|
|
return getFilenameForPath(projectWindows.getActiveID());
|
2017-02-02 19:11:52 +00:00
|
|
|
}
|
|
|
|
|
2016-12-16 01:21:51 +00:00
|
|
|
function _shareFile(e) {
|
2018-06-30 04:42:21 +00:00
|
|
|
if (current_output == null) { // TODO
|
2016-12-30 23:51:15 +00:00
|
|
|
alert("Please fix errors before sharing.");
|
|
|
|
return true;
|
|
|
|
}
|
2018-07-03 14:22:21 +00:00
|
|
|
var text = projectWindows.getCurrentText();
|
|
|
|
if (!text) return false;
|
2017-01-25 17:30:05 +00:00
|
|
|
var github = new Octokat();
|
|
|
|
var files = {};
|
2018-08-05 14:00:53 +00:00
|
|
|
files[getCurrentEditorFilename()] = {"content": text};
|
2017-01-25 17:30:05 +00:00
|
|
|
var gistdata = {
|
|
|
|
"description": '8bitworkshop.com {"platform":"' + platform_id + '"}',
|
|
|
|
"public": true,
|
|
|
|
"files": files
|
|
|
|
};
|
|
|
|
var gist = github.gists.create(gistdata).done(function(val) {
|
|
|
|
var url = "http://8bitworkshop.com/?sharekey=" + val.id;
|
|
|
|
window.prompt("Copy link to clipboard (Ctrl+C, Enter)", url);
|
|
|
|
}).fail(function(err) {
|
|
|
|
alert("Error sharing file: " + err.message);
|
2016-12-16 01:21:51 +00:00
|
|
|
});
|
2016-12-30 23:51:15 +00:00
|
|
|
return true;
|
2016-12-16 01:21:51 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
function _resetPreset(e) {
|
2018-06-28 04:18:16 +00:00
|
|
|
if (!current_preset_entry) {
|
2017-01-03 01:42:15 +00:00
|
|
|
alert("Can only reset built-in file examples.")
|
2018-06-28 04:18:16 +00:00
|
|
|
} else if (confirm("Reset '" + current_preset_entry.name + "' to default?")) {
|
2016-12-16 01:21:51 +00:00
|
|
|
qs['reset'] = '1';
|
2017-01-16 19:13:03 +00:00
|
|
|
gotoNewLocation();
|
2016-12-16 01:21:51 +00:00
|
|
|
}
|
2016-12-30 23:51:15 +00:00
|
|
|
return true;
|
2016-12-16 01:21:51 +00:00
|
|
|
}
|
|
|
|
|
2017-02-02 19:11:52 +00:00
|
|
|
function _downloadROMImage(e) {
|
2018-06-30 04:42:21 +00:00
|
|
|
if (current_output == null) { // TODO
|
2017-02-02 19:11:52 +00:00
|
|
|
alert("Please fix errors before downloading ROM.");
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
var blob = new Blob([current_output], {type: "application/octet-stream"});
|
2018-08-05 14:00:53 +00:00
|
|
|
saveAs(blob, getCurrentMainFilename()+".rom");
|
2017-02-02 19:11:52 +00:00
|
|
|
}
|
|
|
|
|
2018-03-23 21:05:08 +00:00
|
|
|
function _downloadSourceFile(e) {
|
2018-07-03 14:22:21 +00:00
|
|
|
var text = projectWindows.getCurrentText();
|
|
|
|
if (!text) return false;
|
|
|
|
var blob = new Blob([text], {type: "text/plain;charset=utf-8"});
|
2018-08-05 14:00:53 +00:00
|
|
|
saveAs(blob, getCurrentEditorFilename());
|
2018-03-23 21:05:08 +00:00
|
|
|
}
|
|
|
|
|
2016-12-16 01:21:51 +00:00
|
|
|
function populateExamples(sel) {
|
2018-06-26 06:56:36 +00:00
|
|
|
// make sure to use callback so it follows other sections
|
|
|
|
store.length(function(err, len) {
|
2018-07-08 03:10:51 +00:00
|
|
|
sel.append($("<option />").text("--------- Examples ---------").attr('disabled','true'));
|
2018-06-26 06:56:36 +00:00
|
|
|
for (var i=0; i<PRESETS.length; i++) {
|
|
|
|
var preset = PRESETS[i];
|
|
|
|
var name = preset.chapter ? (preset.chapter + ". " + preset.name) : preset.name;
|
2018-07-08 03:10:51 +00:00
|
|
|
sel.append($("<option />").val(preset.id).text(name).attr('selected',(preset.id==main_file_id)?'selected':null));
|
2018-06-26 06:56:36 +00:00
|
|
|
}
|
|
|
|
});
|
2016-12-16 01:21:51 +00:00
|
|
|
}
|
|
|
|
|
2018-06-26 06:56:36 +00:00
|
|
|
function populateFiles(sel, category, prefix) {
|
2018-07-08 03:10:51 +00:00
|
|
|
store.keys(function(err, keys : string[]) {
|
2018-06-26 06:56:36 +00:00
|
|
|
var foundSelected = false;
|
|
|
|
var numFound = 0;
|
|
|
|
if (!keys) keys = [];
|
|
|
|
for (var i = 0; i < keys.length; i++) {
|
|
|
|
var key = keys[i];
|
|
|
|
if (key.startsWith(prefix)) {
|
|
|
|
if (numFound++ == 0)
|
2018-07-08 03:10:51 +00:00
|
|
|
sel.append($("<option />").text("------- " + category + " -------").attr('disabled','true'));
|
2018-06-26 06:56:36 +00:00
|
|
|
var name = key.substring(prefix.length);
|
2018-07-08 03:10:51 +00:00
|
|
|
sel.append($("<option />").val(key).text(name).attr('selected',(key==main_file_id)?'selected':null));
|
2018-07-03 03:45:08 +00:00
|
|
|
if (key == main_file_id) foundSelected = true;
|
2018-06-26 06:56:36 +00:00
|
|
|
}
|
|
|
|
}
|
2018-07-03 03:45:08 +00:00
|
|
|
if (!foundSelected && main_file_id && main_file_id.startsWith(prefix)) {
|
2018-07-08 03:10:51 +00:00
|
|
|
var name = main_file_id.substring(prefix.length);
|
2018-06-26 06:56:36 +00:00
|
|
|
var key = prefix + name;
|
2018-07-08 03:10:51 +00:00
|
|
|
sel.append($("<option />").val(key).text(name).attr('selected','true'));
|
2018-06-26 06:56:36 +00:00
|
|
|
}
|
|
|
|
});
|
2016-12-16 01:21:51 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
function updateSelector() {
|
|
|
|
var sel = $("#preset_select").empty();
|
2017-04-29 15:31:11 +00:00
|
|
|
if (platform_id != 'base_z80') { // TODO
|
|
|
|
populateFiles(sel, "Local Files", "local/");
|
|
|
|
populateFiles(sel, "Shared", "shared/");
|
|
|
|
}
|
2016-12-16 01:21:51 +00:00
|
|
|
populateExamples(sel);
|
|
|
|
// set click handlers
|
|
|
|
sel.off('change').change(function(e) {
|
2018-06-28 04:57:06 +00:00
|
|
|
reloadPresetNamed($(this).val());
|
2016-12-16 01:21:51 +00:00
|
|
|
});
|
|
|
|
}
|
|
|
|
|
2018-07-26 13:43:49 +00:00
|
|
|
function setCompileOutput(data: WorkerResult) {
|
2018-07-02 13:34:20 +00:00
|
|
|
// errors? mark them in editor
|
2018-06-25 23:47:40 +00:00
|
|
|
if (data.errors && data.errors.length > 0) {
|
2018-07-26 13:43:49 +00:00
|
|
|
projectWindows.setErrors(data.errors);
|
2018-07-03 04:21:08 +00:00
|
|
|
toolbar.addClass("has-errors");
|
2016-12-16 01:21:51 +00:00
|
|
|
} else {
|
2018-07-03 14:22:21 +00:00
|
|
|
// process symbol map
|
2018-06-30 04:42:21 +00:00
|
|
|
symbolmap = data.symbolmap;
|
|
|
|
addr2symbol = invertMap(symbolmap);
|
|
|
|
if (!addr2symbol[0x0]) addr2symbol[0x0] = '__START__'; // needed for ...
|
|
|
|
addr2symbol[0x10000] = '__END__'; // needed for dump memory to work
|
|
|
|
compparams = data.params;
|
2016-12-16 01:21:51 +00:00
|
|
|
// load ROM
|
2017-03-24 22:10:35 +00:00
|
|
|
var rom = data.output;
|
2018-07-10 01:46:45 +00:00
|
|
|
if (rom) { // TODO instanceof Uint8Array) {
|
2016-12-16 01:21:51 +00:00
|
|
|
try {
|
2016-12-31 16:05:22 +00:00
|
|
|
platform.loadROM(getCurrentPresetTitle(), rom);
|
2017-11-28 02:08:19 +00:00
|
|
|
if (!userPaused) resume();
|
2016-12-16 01:21:51 +00:00
|
|
|
current_output = rom;
|
2018-08-02 17:08:37 +00:00
|
|
|
// TODO: reset profiler etc? (Tell views?)
|
2016-12-16 01:21:51 +00:00
|
|
|
} catch (e) {
|
2018-07-03 14:22:21 +00:00
|
|
|
console.log(e);
|
2017-01-16 19:13:03 +00:00
|
|
|
toolbar.addClass("has-errors");
|
2018-08-02 17:08:37 +00:00
|
|
|
projectWindows.setErrors([{line:1,msg:e+""}]); // TODO: doesn't work
|
2016-12-16 01:21:51 +00:00
|
|
|
current_output = null;
|
|
|
|
}
|
|
|
|
}
|
2018-07-03 14:22:21 +00:00
|
|
|
// update all windows (listings)
|
2018-08-02 17:08:37 +00:00
|
|
|
projectWindows.refresh(false);
|
2016-12-16 01:21:51 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-07-29 20:26:05 +00:00
|
|
|
function showDebugInfo(state?) {
|
2018-07-29 19:53:50 +00:00
|
|
|
var meminfo = $("#mem_info");
|
2018-07-29 20:26:05 +00:00
|
|
|
var allcats = platform.getDebugCategories && platform.getDebugCategories();
|
|
|
|
if (allcats && !debugCategory)
|
|
|
|
debugCategory = allcats[0];
|
|
|
|
var s = state && platform.getDebugInfo && platform.getDebugInfo(debugCategory, state);
|
2018-06-18 08:12:52 +00:00
|
|
|
if (s) {
|
2016-12-16 01:21:51 +00:00
|
|
|
var hs = lastDebugInfo ? highlightDifferences(lastDebugInfo, s) : s;
|
2018-07-29 19:53:50 +00:00
|
|
|
meminfo.show().html(hs);
|
2018-07-29 20:26:05 +00:00
|
|
|
var catspan = $('<span>');
|
|
|
|
var addCategoryLink = (cat:string) => {
|
|
|
|
var catlink = $('<a>'+cat+'</a>');
|
|
|
|
if (cat == debugCategory)
|
|
|
|
catlink.addClass('selected');
|
|
|
|
catlink.click((e) => {
|
|
|
|
debugCategory = cat;
|
|
|
|
lastDebugInfo = null;
|
|
|
|
showDebugInfo(lastDebugState);
|
|
|
|
});
|
|
|
|
catspan.append(catlink);
|
|
|
|
catspan.append('<span> </span>');
|
|
|
|
}
|
|
|
|
for (var cat of allcats) {
|
|
|
|
addCategoryLink(cat);
|
|
|
|
}
|
|
|
|
meminfo.append('<br>');
|
|
|
|
meminfo.append(catspan);
|
2016-12-16 01:21:51 +00:00
|
|
|
lastDebugInfo = s;
|
|
|
|
} else {
|
2018-07-29 19:53:50 +00:00
|
|
|
meminfo.hide();
|
2016-12-16 01:21:51 +00:00
|
|
|
lastDebugInfo = null;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-07-08 14:07:19 +00:00
|
|
|
function setDebugButtonState(btnid:string, btnstate:string) {
|
2018-07-07 05:09:15 +00:00
|
|
|
$("#debug_bar").find("button").removeClass("btn_active").removeClass("btn_stopped");
|
|
|
|
$("#dbg_"+btnid).addClass("btn_"+btnstate);
|
|
|
|
}
|
|
|
|
|
2018-07-08 03:10:51 +00:00
|
|
|
function setupBreakpoint(btnid? : string) {
|
2016-12-31 16:05:22 +00:00
|
|
|
platform.setupDebug(function(state) {
|
2017-01-06 14:49:07 +00:00
|
|
|
lastDebugState = state;
|
2018-07-29 20:26:05 +00:00
|
|
|
showDebugInfo(state);
|
2018-08-02 17:08:37 +00:00
|
|
|
projectWindows.refresh(true);
|
2018-07-07 05:09:15 +00:00
|
|
|
if (btnid) setDebugButtonState(btnid, "stopped");
|
2016-12-31 16:05:22 +00:00
|
|
|
});
|
2018-07-07 05:09:15 +00:00
|
|
|
if (btnid) setDebugButtonState(btnid, "active");
|
2016-12-16 01:21:51 +00:00
|
|
|
}
|
|
|
|
|
2017-11-16 17:08:06 +00:00
|
|
|
function _pause() {
|
2016-12-31 16:05:22 +00:00
|
|
|
if (platform.isRunning()) {
|
|
|
|
platform.pause();
|
2018-02-21 18:54:53 +00:00
|
|
|
console.log("Paused");
|
2016-12-16 01:21:51 +00:00
|
|
|
}
|
2018-07-07 05:09:15 +00:00
|
|
|
setDebugButtonState("pause", "stopped");
|
2016-12-16 01:21:51 +00:00
|
|
|
}
|
|
|
|
|
2017-11-16 17:08:06 +00:00
|
|
|
function pause() {
|
2016-12-16 01:21:51 +00:00
|
|
|
clearBreakpoint();
|
2017-11-16 17:08:06 +00:00
|
|
|
_pause();
|
2017-11-28 02:08:19 +00:00
|
|
|
userPaused = true;
|
2017-11-16 17:08:06 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
function _resume() {
|
2016-12-31 16:05:22 +00:00
|
|
|
if (! platform.isRunning()) {
|
|
|
|
platform.resume();
|
2018-02-21 18:54:53 +00:00
|
|
|
console.log("Resumed");
|
2016-12-16 01:21:51 +00:00
|
|
|
}
|
2018-07-07 05:09:15 +00:00
|
|
|
setDebugButtonState("go", "active");
|
2017-11-16 17:08:06 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
function resume() {
|
|
|
|
clearBreakpoint();
|
2018-06-24 17:39:08 +00:00
|
|
|
if (! platform.isRunning() ) {
|
2018-08-02 17:08:37 +00:00
|
|
|
projectWindows.refresh(false);
|
2018-06-24 17:39:08 +00:00
|
|
|
}
|
2017-11-16 17:08:06 +00:00
|
|
|
_resume();
|
2017-11-28 02:08:19 +00:00
|
|
|
userPaused = false;
|
2016-12-16 01:21:51 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
function singleStep() {
|
2018-07-07 05:09:15 +00:00
|
|
|
setupBreakpoint("step");
|
2016-12-31 16:05:22 +00:00
|
|
|
platform.step();
|
2016-12-16 01:21:51 +00:00
|
|
|
}
|
|
|
|
|
2017-11-24 19:14:22 +00:00
|
|
|
function singleFrameStep() {
|
2018-07-07 05:09:15 +00:00
|
|
|
setupBreakpoint("tovsync");
|
2017-11-24 19:14:22 +00:00
|
|
|
platform.runToVsync();
|
|
|
|
}
|
|
|
|
|
2018-07-08 14:07:19 +00:00
|
|
|
function getEditorPC() : number {
|
2018-07-03 14:22:21 +00:00
|
|
|
var wnd = projectWindows.getActive();
|
|
|
|
return wnd && wnd.getCursorPC && wnd.getCursorPC();
|
2017-02-05 04:19:54 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
function runToCursor() {
|
2018-07-07 05:09:15 +00:00
|
|
|
setupBreakpoint("toline");
|
2018-07-02 13:34:20 +00:00
|
|
|
var pc = getEditorPC();
|
2017-01-14 02:31:04 +00:00
|
|
|
if (pc >= 0) {
|
2017-02-05 04:19:54 +00:00
|
|
|
console.log("Run to", pc.toString(16));
|
2018-06-18 08:12:52 +00:00
|
|
|
if (platform.runToPC) {
|
|
|
|
platform.runToPC(pc);
|
|
|
|
} else {
|
|
|
|
platform.runEval(function(c) {
|
|
|
|
return c.PC == pc;
|
|
|
|
});
|
|
|
|
}
|
2016-12-16 01:21:51 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-01-07 18:05:02 +00:00
|
|
|
function runUntilReturn() {
|
2018-07-07 05:09:15 +00:00
|
|
|
setupBreakpoint("stepout");
|
2017-01-14 02:31:04 +00:00
|
|
|
platform.runUntilReturn();
|
2017-01-07 18:05:02 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
function runStepBackwards() {
|
2018-07-07 05:09:15 +00:00
|
|
|
setupBreakpoint("stepback");
|
2017-01-07 18:05:02 +00:00
|
|
|
platform.stepBack();
|
|
|
|
}
|
|
|
|
|
2016-12-16 01:21:51 +00:00
|
|
|
function clearBreakpoint() {
|
2017-01-06 14:49:07 +00:00
|
|
|
lastDebugState = null;
|
2017-11-11 19:45:32 +00:00
|
|
|
if (platform.clearDebug) platform.clearDebug();
|
2018-07-29 20:26:05 +00:00
|
|
|
showDebugInfo();
|
2016-12-16 01:21:51 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
function resetAndDebug() {
|
2017-11-29 01:48:27 +00:00
|
|
|
if (platform.setupDebug && platform.readAddress) { // TODO??
|
2017-11-11 19:45:32 +00:00
|
|
|
clearBreakpoint();
|
2017-11-16 17:08:06 +00:00
|
|
|
_resume();
|
2017-11-11 19:45:32 +00:00
|
|
|
platform.reset();
|
2018-07-07 05:09:15 +00:00
|
|
|
setupBreakpoint("reset");
|
2018-06-22 06:24:52 +00:00
|
|
|
if (platform.runEval)
|
|
|
|
platform.runEval(function(c) { return true; }); // break immediately
|
|
|
|
else
|
|
|
|
; // TODO???
|
2017-11-11 19:45:32 +00:00
|
|
|
} else {
|
|
|
|
platform.reset();
|
|
|
|
}
|
2017-01-03 01:42:15 +00:00
|
|
|
}
|
2017-01-06 16:57:28 +00:00
|
|
|
|
2018-07-11 15:17:37 +00:00
|
|
|
var lastBreakExpr = "c.PC == 0x6000";
|
2017-01-07 18:05:02 +00:00
|
|
|
function _breakExpression() {
|
2018-06-27 02:32:34 +00:00
|
|
|
var exprs = window.prompt("Enter break expression", lastBreakExpr);
|
2017-01-07 18:05:02 +00:00
|
|
|
if (exprs) {
|
|
|
|
var fn = new Function('c', 'return (' + exprs + ');');
|
|
|
|
setupBreakpoint();
|
|
|
|
platform.runEval(fn);
|
2018-06-27 02:32:34 +00:00
|
|
|
lastBreakExpr = exprs;
|
2017-01-07 18:05:02 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-07-08 14:07:19 +00:00
|
|
|
function getSymbolAtAddress(a : number) {
|
2017-04-22 01:56:49 +00:00
|
|
|
if (addr2symbol[a]) return addr2symbol[a];
|
|
|
|
var i=0;
|
|
|
|
while (--a >= 0) {
|
|
|
|
i++;
|
|
|
|
if (addr2symbol[a]) return addr2symbol[a] + '+' + i;
|
|
|
|
}
|
|
|
|
return '';
|
|
|
|
}
|
|
|
|
|
2017-04-19 01:18:53 +00:00
|
|
|
function updateDebugWindows() {
|
|
|
|
if (platform.isRunning()) {
|
2018-07-02 13:34:20 +00:00
|
|
|
projectWindows.tick();
|
2017-04-19 01:18:53 +00:00
|
|
|
}
|
|
|
|
setTimeout(updateDebugWindows, 200);
|
|
|
|
}
|
|
|
|
|
2017-05-20 19:13:23 +00:00
|
|
|
function _recordVideo() {
|
|
|
|
var canvas = $("#emulator").find("canvas")[0];
|
|
|
|
if (!canvas) {
|
|
|
|
alert("Could not find canvas element to record video!");
|
|
|
|
return;
|
|
|
|
}
|
2017-05-25 19:49:30 +00:00
|
|
|
var rotate = 0;
|
|
|
|
if (canvas.style && canvas.style.transform) {
|
|
|
|
if (canvas.style.transform.indexOf("rotate(-90deg)") >= 0)
|
|
|
|
rotate = -1;
|
|
|
|
else if (canvas.style.transform.indexOf("rotate(90deg)") >= 0)
|
|
|
|
rotate = 1;
|
|
|
|
}
|
|
|
|
var gif = new GIF({
|
|
|
|
workerScript: 'gif.js/dist/gif.worker.js',
|
|
|
|
workers: 4,
|
|
|
|
quality: 10,
|
|
|
|
rotate: rotate
|
|
|
|
});
|
2017-05-20 19:13:23 +00:00
|
|
|
var img = $('#videoPreviewImage');
|
|
|
|
//img.attr('src', 'https://articulate-heroes.s3.amazonaws.com/uploads/rte/kgrtehja_DancingBannana.gif');
|
|
|
|
gif.on('finished', function(blob) {
|
|
|
|
img.attr('src', URL.createObjectURL(blob));
|
2017-05-25 19:49:30 +00:00
|
|
|
$("#pleaseWaitModal").modal('hide');
|
2017-11-16 17:08:06 +00:00
|
|
|
_resume();
|
2017-05-20 19:13:23 +00:00
|
|
|
$("#videoPreviewModal").modal('show');
|
|
|
|
});
|
|
|
|
var intervalMsec = 17;
|
|
|
|
var maxFrames = 500;
|
|
|
|
var nframes = 0;
|
|
|
|
console.log("Recording video", canvas);
|
|
|
|
var f = function() {
|
|
|
|
if (nframes++ > maxFrames) {
|
|
|
|
console.log("Rendering video");
|
2017-05-25 19:49:30 +00:00
|
|
|
$("#pleaseWaitModal").modal('show');
|
2017-11-16 17:08:06 +00:00
|
|
|
_pause();
|
2017-05-20 19:13:23 +00:00
|
|
|
gif.render();
|
|
|
|
} else {
|
2017-05-25 19:49:30 +00:00
|
|
|
gif.addFrame(canvas, {delay: intervalMsec, copy: true});
|
2017-05-20 19:13:23 +00:00
|
|
|
setTimeout(f, intervalMsec);
|
|
|
|
}
|
|
|
|
};
|
|
|
|
f();
|
|
|
|
}
|
|
|
|
|
2018-07-08 14:07:19 +00:00
|
|
|
function setFrameRateUI(fps:number) {
|
2018-02-26 23:18:23 +00:00
|
|
|
platform.setFrameRate(fps);
|
|
|
|
if (fps > 0.01)
|
|
|
|
$("#fps_label").text(fps.toFixed(2));
|
|
|
|
else
|
|
|
|
$("#fps_label").text("1/"+Math.round(1/fps));
|
|
|
|
}
|
|
|
|
|
|
|
|
function _slowerFrameRate() {
|
|
|
|
var fps = platform.getFrameRate();
|
|
|
|
fps = fps/2;
|
|
|
|
if (fps > 0.00001) setFrameRateUI(fps);
|
|
|
|
}
|
|
|
|
|
|
|
|
function _fasterFrameRate() {
|
|
|
|
var fps = platform.getFrameRate();
|
|
|
|
fps = Math.min(60, fps*2);
|
|
|
|
setFrameRateUI(fps);
|
|
|
|
}
|
|
|
|
|
2018-02-27 04:48:36 +00:00
|
|
|
function _slowestFrameRate() {
|
|
|
|
setFrameRateUI(60/65536);
|
|
|
|
}
|
|
|
|
|
|
|
|
function _fastestFrameRate() {
|
2018-07-07 05:09:15 +00:00
|
|
|
_resume();
|
2018-02-27 04:48:36 +00:00
|
|
|
setFrameRateUI(60);
|
|
|
|
}
|
|
|
|
|
2018-06-30 02:06:14 +00:00
|
|
|
function _openBitmapEditor() {
|
2018-07-04 15:36:32 +00:00
|
|
|
var wnd = projectWindows.getActive();
|
2018-07-03 14:22:21 +00:00
|
|
|
if (wnd && wnd.openBitmapEditorAtCursor)
|
2018-07-04 15:36:32 +00:00
|
|
|
wnd.openBitmapEditorAtCursor();
|
|
|
|
}
|
|
|
|
|
|
|
|
function traceTiming() {
|
2018-08-02 17:08:37 +00:00
|
|
|
projectWindows.refresh(false);
|
2018-07-04 15:36:32 +00:00
|
|
|
var wnd = projectWindows.getActive();
|
|
|
|
if (wnd.getSourceFile && wnd.setGutterBytes) { // is editor active?
|
|
|
|
showLoopTimingForPC(0, wnd.getSourceFile(), wnd);
|
|
|
|
}
|
2018-06-30 02:06:14 +00:00
|
|
|
}
|
|
|
|
|
2016-12-16 01:21:51 +00:00
|
|
|
function setupDebugControls(){
|
|
|
|
$("#dbg_reset").click(resetAndDebug);
|
|
|
|
$("#dbg_pause").click(pause);
|
|
|
|
$("#dbg_go").click(resume);
|
2017-11-24 19:14:22 +00:00
|
|
|
|
|
|
|
if (platform.step)
|
2017-11-11 19:45:32 +00:00
|
|
|
$("#dbg_step").click(singleStep).show();
|
2017-11-24 19:14:22 +00:00
|
|
|
else
|
2017-11-11 19:45:32 +00:00
|
|
|
$("#dbg_step").hide();
|
2017-11-24 19:14:22 +00:00
|
|
|
if (platform.runToVsync)
|
|
|
|
$("#dbg_tovsync").click(singleFrameStep).show();
|
|
|
|
else
|
|
|
|
$("#dbg_tovsync").hide();
|
2018-06-18 08:12:52 +00:00
|
|
|
if ((platform.runEval || platform.runToPC) && platform_id != 'verilog')
|
2017-11-24 19:14:22 +00:00
|
|
|
$("#dbg_toline").click(runToCursor).show();
|
|
|
|
else
|
2017-11-11 19:45:32 +00:00
|
|
|
$("#dbg_toline").hide();
|
2017-11-24 19:14:22 +00:00
|
|
|
if (platform.runUntilReturn)
|
|
|
|
$("#dbg_stepout").click(runUntilReturn).show();
|
|
|
|
else
|
2017-11-11 19:45:32 +00:00
|
|
|
$("#dbg_stepout").hide();
|
2017-11-24 19:14:22 +00:00
|
|
|
if (platform.stepBack)
|
|
|
|
$("#dbg_stepback").click(runStepBackwards).show();
|
|
|
|
else
|
2017-11-11 19:45:32 +00:00
|
|
|
$("#dbg_stepback").hide();
|
2017-11-24 19:14:22 +00:00
|
|
|
|
2018-07-08 03:10:51 +00:00
|
|
|
if (window['showLoopTimingForPC']) { // VCS-only (TODO: put in platform)
|
2017-01-16 15:35:19 +00:00
|
|
|
$("#dbg_timing").click(traceTiming).show();
|
|
|
|
}
|
2017-01-06 14:49:07 +00:00
|
|
|
$("#disassembly").hide();
|
2018-06-30 02:06:14 +00:00
|
|
|
$("#dbg_bitmap").click(_openBitmapEditor);
|
2016-12-30 23:51:15 +00:00
|
|
|
$(".dropdown-menu").collapse({toggle: false});
|
|
|
|
$("#item_new_file").click(_createNewFile);
|
2018-06-26 23:57:03 +00:00
|
|
|
$("#item_upload_file").click(_uploadNewFile);
|
2016-12-30 23:51:15 +00:00
|
|
|
$("#item_share_file").click(_shareFile);
|
|
|
|
$("#item_reset_file").click(_resetPreset);
|
2017-11-24 19:14:22 +00:00
|
|
|
if (platform.runEval)
|
|
|
|
$("#item_debug_expr").click(_breakExpression).show();
|
|
|
|
else
|
|
|
|
$("#item_debug_expr").hide();
|
2017-02-02 19:11:52 +00:00
|
|
|
$("#item_download_rom").click(_downloadROMImage);
|
2018-03-23 21:05:08 +00:00
|
|
|
$("#item_download_file").click(_downloadSourceFile);
|
2017-05-20 19:13:23 +00:00
|
|
|
$("#item_record_video").click(_recordVideo);
|
2018-02-26 23:18:23 +00:00
|
|
|
if (platform.setFrameRate && platform.getFrameRate) {
|
|
|
|
$("#speed_bar").show();
|
|
|
|
$("#dbg_slower").click(_slowerFrameRate);
|
|
|
|
$("#dbg_faster").click(_fasterFrameRate);
|
2018-02-27 04:48:36 +00:00
|
|
|
$("#dbg_slowest").click(_slowestFrameRate);
|
|
|
|
$("#dbg_fastest").click(_fastestFrameRate);
|
2018-02-26 23:18:23 +00:00
|
|
|
}
|
2017-04-19 01:18:53 +00:00
|
|
|
updateDebugWindows();
|
2016-12-16 01:21:51 +00:00
|
|
|
}
|
|
|
|
|
2016-12-18 20:59:31 +00:00
|
|
|
function showWelcomeMessage() {
|
2017-05-01 11:37:48 +00:00
|
|
|
if (!localStorage.getItem("8bitworkshop.hello")) {
|
2016-12-30 23:51:15 +00:00
|
|
|
// Instance the tour
|
2017-04-20 00:55:13 +00:00
|
|
|
var is_vcs = platform_id == 'vcs';
|
2018-07-06 23:12:58 +00:00
|
|
|
var steps = [
|
2016-12-30 23:51:15 +00:00
|
|
|
{
|
2018-07-06 23:12:58 +00:00
|
|
|
element: "#workspace",
|
2016-12-30 23:51:15 +00:00
|
|
|
title: "Welcome to 8bitworkshop!",
|
2017-04-20 00:55:13 +00:00
|
|
|
content: is_vcs ? "Type your 6502 assembly code into the editor, and it'll be assembled in real-time. All changes are saved to browser local storage."
|
2018-07-06 23:12:58 +00:00
|
|
|
: "Type your source code into the editor, and it'll be compiled in real-time. All changes are saved to browser local storage."
|
2016-12-30 23:51:15 +00:00
|
|
|
},
|
|
|
|
{
|
|
|
|
element: "#emulator",
|
|
|
|
placement: 'left',
|
2017-04-20 00:55:13 +00:00
|
|
|
title: "Emulator",
|
|
|
|
content: "This is an emulator for the \"" + platform_id + "\" platform. We'll load your compiled code into the emulator whenever you make changes."
|
2016-12-30 23:51:15 +00:00
|
|
|
},
|
|
|
|
{
|
|
|
|
element: "#preset_select",
|
|
|
|
title: "File Selector",
|
|
|
|
content: "Pick a code example from the book, or access your own files and files shared by others."
|
|
|
|
},
|
|
|
|
{
|
|
|
|
element: "#debug_bar",
|
|
|
|
placement: 'bottom',
|
|
|
|
title: "Debug Tools",
|
2017-04-20 00:55:13 +00:00
|
|
|
content: "Use these buttons to set breakpoints, single step through code, pause/resume, and use debugging tools."
|
2016-12-30 23:51:15 +00:00
|
|
|
},
|
|
|
|
{
|
|
|
|
element: "#dropdownMenuButton",
|
|
|
|
title: "Main Menu",
|
2017-04-20 00:55:13 +00:00
|
|
|
content: "Click the menu to switch between platforms, create new files, or share your work with others."
|
2018-07-06 23:12:58 +00:00
|
|
|
}];
|
|
|
|
if (!is_vcs) {
|
|
|
|
steps.push({
|
|
|
|
element: "#windowMenuButton",
|
|
|
|
title: "Window List",
|
|
|
|
content: "Switch between editor windows, assembly listings, and other tools like disassembler and memory dump."
|
|
|
|
});
|
|
|
|
}
|
2018-07-07 14:55:27 +00:00
|
|
|
steps.push({
|
|
|
|
element: "#booksMenuButton",
|
|
|
|
placement: 'left',
|
|
|
|
title: "Bookstore",
|
|
|
|
content: "Get some books that explain how to program all of this stuff!"
|
|
|
|
});
|
2018-07-06 23:12:58 +00:00
|
|
|
var tour = new Tour({
|
|
|
|
autoscroll:false,
|
|
|
|
//storage:false,
|
|
|
|
steps:steps
|
|
|
|
});
|
2016-12-30 23:51:15 +00:00
|
|
|
tour.init();
|
2017-01-03 15:43:40 +00:00
|
|
|
setTimeout(function() { tour.start(); }, 2000);
|
2016-12-18 20:59:31 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-12-16 01:21:51 +00:00
|
|
|
///////////////////////////////////////////////////
|
|
|
|
|
2018-07-08 03:10:51 +00:00
|
|
|
var qs = (function (a : string[]) {
|
|
|
|
if (!a || a.length == 0)
|
2016-12-16 01:21:51 +00:00
|
|
|
return {};
|
|
|
|
var b = {};
|
|
|
|
for (var i = 0; i < a.length; ++i) {
|
|
|
|
var p = a[i].split('=', 2);
|
|
|
|
if (p.length == 1)
|
|
|
|
b[p[0]] = "";
|
|
|
|
else
|
|
|
|
b[p[0]] = decodeURIComponent(p[1].replace(/\+/g, " "));
|
|
|
|
}
|
|
|
|
return b;
|
|
|
|
})(window.location.search.substr(1).split('&'));
|
|
|
|
|
2018-07-04 02:14:07 +00:00
|
|
|
// catch errors
|
|
|
|
function installErrorHandler() {
|
|
|
|
if (typeof window.onerror == "object") {
|
|
|
|
window.onerror = function (msgevent, url, line, col, error) {
|
|
|
|
console.log(msgevent, url, line, col);
|
|
|
|
console.log(error);
|
2018-07-06 06:42:01 +00:00
|
|
|
ga('send', 'exception', {
|
|
|
|
'exDescription': msgevent + " " + url + " " + " " + line + ":" + col + ", " + error,
|
|
|
|
'exFatal': true
|
|
|
|
});
|
2018-07-04 02:14:07 +00:00
|
|
|
alert(msgevent+"");
|
|
|
|
};
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
function uninstallErrorHandler() {
|
|
|
|
window.onerror = null;
|
|
|
|
}
|
|
|
|
|
|
|
|
function gotoNewLocation() {
|
|
|
|
uninstallErrorHandler();
|
2018-07-08 03:10:51 +00:00
|
|
|
window.location.href = "?" + $.param(qs);
|
2018-07-04 02:14:07 +00:00
|
|
|
}
|
|
|
|
|
2017-01-25 17:30:05 +00:00
|
|
|
function initPlatform() {
|
2018-06-28 04:18:16 +00:00
|
|
|
store = createNewPersistentStore(platform_id);
|
2017-01-25 17:30:05 +00:00
|
|
|
}
|
|
|
|
|
2017-04-26 19:44:55 +00:00
|
|
|
function showBookLink() {
|
|
|
|
if (platform_id == 'vcs')
|
|
|
|
$("#booklink_vcs").show();
|
2017-11-15 00:12:52 +00:00
|
|
|
else if (platform_id == 'mw8080bw' || platform_id == 'vicdual' || platform_id == 'galaxian-scramble' || platform_id == 'vector-z80color' || platform_id == 'williams-z80')
|
2017-04-26 19:44:55 +00:00
|
|
|
$("#booklink_arcade").show();
|
|
|
|
}
|
|
|
|
|
2017-05-01 15:30:47 +00:00
|
|
|
function addPageFocusHandlers() {
|
2017-05-02 13:09:53 +00:00
|
|
|
var hidden = false;
|
2017-05-01 15:30:47 +00:00
|
|
|
document.addEventListener("visibilitychange", function() {
|
2017-05-02 13:09:53 +00:00
|
|
|
if (document.visibilityState == 'hidden' && platform.isRunning()) {
|
2017-11-16 17:08:06 +00:00
|
|
|
_pause();
|
2017-05-02 13:09:53 +00:00
|
|
|
hidden = true;
|
|
|
|
} else if (document.visibilityState == 'visible' && hidden) {
|
2017-11-16 17:08:06 +00:00
|
|
|
_resume();
|
2017-05-02 13:09:53 +00:00
|
|
|
hidden = false;
|
|
|
|
}
|
|
|
|
});
|
|
|
|
$(window).on("focus", function() {
|
|
|
|
if (hidden) {
|
2017-11-16 17:08:06 +00:00
|
|
|
_resume();
|
2017-05-02 13:09:53 +00:00
|
|
|
hidden = false;
|
|
|
|
}
|
|
|
|
});
|
|
|
|
$(window).on("blur", function() {
|
|
|
|
if (platform.isRunning()) {
|
2017-11-16 17:08:06 +00:00
|
|
|
_pause();
|
2017-05-02 13:09:53 +00:00
|
|
|
hidden = true;
|
|
|
|
}
|
2017-05-01 15:30:47 +00:00
|
|
|
});
|
|
|
|
}
|
|
|
|
|
2017-01-14 16:14:25 +00:00
|
|
|
function startPlatform() {
|
2017-01-25 17:30:05 +00:00
|
|
|
initPlatform();
|
2017-01-29 21:06:05 +00:00
|
|
|
if (!PLATFORMS[platform_id]) throw Error("Invalid platform '" + platform_id + "'.");
|
2017-01-14 16:14:25 +00:00
|
|
|
platform = new PLATFORMS[platform_id]($("#emulator")[0]);
|
|
|
|
PRESETS = platform.getPresets();
|
|
|
|
if (qs['file']) {
|
2017-01-16 15:35:19 +00:00
|
|
|
// start platform and load file
|
|
|
|
platform.start();
|
2017-04-22 01:56:49 +00:00
|
|
|
setupDebugControls();
|
2018-06-29 23:44:04 +00:00
|
|
|
initProject();
|
|
|
|
loadProject(qs['file']);
|
2017-01-14 16:14:25 +00:00
|
|
|
updateSelector();
|
2017-04-26 19:44:55 +00:00
|
|
|
showBookLink();
|
2017-05-01 15:30:47 +00:00
|
|
|
addPageFocusHandlers();
|
2017-01-16 15:35:19 +00:00
|
|
|
return true;
|
2017-01-14 16:14:25 +00:00
|
|
|
} else {
|
2017-01-16 15:35:19 +00:00
|
|
|
// try to load last file (redirect)
|
2017-01-14 16:14:25 +00:00
|
|
|
var lastid = localStorage.getItem("__lastid_"+platform_id) || localStorage.getItem("__lastid");
|
|
|
|
localStorage.removeItem("__lastid");
|
2018-06-28 04:57:06 +00:00
|
|
|
reloadPresetNamed(lastid || PRESETS[0].id);
|
2017-01-16 15:35:19 +00:00
|
|
|
return false;
|
2017-01-14 16:14:25 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-07-08 14:07:19 +00:00
|
|
|
function loadSharedFile(sharekey : string) {
|
2017-01-25 17:30:05 +00:00
|
|
|
var github = new Octokat();
|
|
|
|
var gist = github.gists(sharekey);
|
|
|
|
gist.fetch().done(function(val) {
|
|
|
|
var filename;
|
|
|
|
for (filename in val.files) { break; }
|
|
|
|
var newid = 'shared/' + filename;
|
|
|
|
var json = JSON.parse(val.description.slice(val.description.indexOf(' ')+1));
|
|
|
|
console.log("Fetched " + newid, json);
|
|
|
|
platform_id = json['platform'];
|
|
|
|
initPlatform();
|
2018-06-29 02:42:47 +00:00
|
|
|
current_project.updateFile(newid, val.files[filename].content);
|
2018-06-29 23:52:09 +00:00
|
|
|
reloadPresetNamed(newid);
|
2017-01-25 17:30:05 +00:00
|
|
|
delete qs['sharekey'];
|
|
|
|
gotoNewLocation();
|
|
|
|
}).fail(function(err) {
|
|
|
|
alert("Error loading share file: " + err.message);
|
|
|
|
});
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2017-01-03 01:42:15 +00:00
|
|
|
// start
|
2018-07-08 14:07:19 +00:00
|
|
|
function startUI(loadplatform : boolean) {
|
2017-01-16 19:13:03 +00:00
|
|
|
installErrorHandler();
|
2017-01-25 17:30:05 +00:00
|
|
|
// add default platform?
|
|
|
|
platform_id = qs['platform'] || localStorage.getItem("__lastplatform");
|
|
|
|
if (!platform_id) {
|
|
|
|
platform_id = qs['platform'] = "vcs";
|
|
|
|
}
|
2018-07-24 15:38:56 +00:00
|
|
|
$("#item_platform_"+platform_id).addClass("dropdown-item-checked");
|
2017-01-14 16:14:25 +00:00
|
|
|
// parse query string
|
|
|
|
// is this a share URL?
|
|
|
|
if (qs['sharekey']) {
|
2017-01-25 17:30:05 +00:00
|
|
|
loadSharedFile(qs['sharekey']);
|
2017-01-14 02:31:04 +00:00
|
|
|
} else {
|
2017-01-14 16:14:25 +00:00
|
|
|
// reset file?
|
|
|
|
if (qs['file'] && qs['reset']) {
|
2017-01-27 02:59:34 +00:00
|
|
|
initPlatform();
|
2018-08-13 22:17:36 +00:00
|
|
|
store.removeItem(qs['fileview'] || qs['file']);
|
2017-01-14 16:14:25 +00:00
|
|
|
qs['reset'] = '';
|
2017-01-16 19:13:03 +00:00
|
|
|
gotoNewLocation();
|
2017-01-14 16:14:25 +00:00
|
|
|
} else {
|
|
|
|
// load and start platform object
|
|
|
|
if (loadplatform) {
|
2018-08-13 21:16:33 +00:00
|
|
|
var scriptfn = 'src/platform/' + platform_id.split(/[.-]/)[0] + '.js';
|
2017-05-01 15:30:47 +00:00
|
|
|
var script = document.createElement('script');
|
|
|
|
script.onload = function() {
|
2017-01-14 16:14:25 +00:00
|
|
|
console.log("loaded platform", platform_id);
|
|
|
|
startPlatform();
|
2017-04-29 15:31:11 +00:00
|
|
|
showWelcomeMessage();
|
2017-05-01 15:30:47 +00:00
|
|
|
};
|
|
|
|
script.src = scriptfn;
|
|
|
|
document.getElementsByTagName('head')[0].appendChild(script);
|
2017-01-14 05:47:26 +00:00
|
|
|
} else {
|
2017-01-14 16:14:25 +00:00
|
|
|
startPlatform();
|
2017-04-29 15:31:11 +00:00
|
|
|
showWelcomeMessage();
|
2017-01-14 05:47:26 +00:00
|
|
|
}
|
2017-01-14 16:14:25 +00:00
|
|
|
}
|
2016-12-16 01:21:51 +00:00
|
|
|
}
|
|
|
|
}
|