moving boardhost to pxt
This commit is contained in:
parent
9db91d89d6
commit
e5d985dbf1
@ -1,43 +1,6 @@
|
|||||||
/// <reference path="../node_modules/pxt-core/built/pxtsim.d.ts"/>
|
/// <reference path="../node_modules/pxt-core/built/pxtsim.d.ts"/>
|
||||||
|
|
||||||
namespace pxsim {
|
namespace pxsim {
|
||||||
export class CoreBoard extends BaseBoard {
|
|
||||||
id: string;
|
|
||||||
|
|
||||||
// the bus
|
|
||||||
bus: pxsim.EventBus;
|
|
||||||
|
|
||||||
// updates
|
|
||||||
updateSubscribers: (() => void)[];
|
|
||||||
|
|
||||||
// builtin
|
|
||||||
builtinParts: Map<any>;
|
|
||||||
builtinVisuals: Map<() => visuals.IBoardPart<any>>;
|
|
||||||
builtinPartVisuals: Map<(xy: visuals.Coord) => visuals.SVGElAndSize>;
|
|
||||||
|
|
||||||
constructor() {
|
|
||||||
super()
|
|
||||||
this.id = "b" + Math_.random(2147483647);
|
|
||||||
this.bus = new pxsim.EventBus(runtime);
|
|
||||||
|
|
||||||
// updates
|
|
||||||
this.updateSubscribers = []
|
|
||||||
this.updateView = () => {
|
|
||||||
this.updateSubscribers.forEach(sub => sub());
|
|
||||||
}
|
|
||||||
|
|
||||||
this.builtinParts = {};
|
|
||||||
this.builtinVisuals = {};
|
|
||||||
this.builtinPartVisuals = {};
|
|
||||||
}
|
|
||||||
|
|
||||||
kill() {
|
|
||||||
super.kill();
|
|
||||||
AudioContextManager.stop();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
export class DalBoard extends CoreBoard {
|
export class DalBoard extends CoreBoard {
|
||||||
// state & update logic for component services
|
// state & update logic for component services
|
||||||
ledMatrixState: LedMatrixState;
|
ledMatrixState: LedMatrixState;
|
||||||
@ -103,15 +66,15 @@ namespace pxsim {
|
|||||||
initAsync(msg: SimulatorRunMessage): Promise<void> {
|
initAsync(msg: SimulatorRunMessage): Promise<void> {
|
||||||
super.initAsync(msg);
|
super.initAsync(msg);
|
||||||
|
|
||||||
let options = (msg.options || {}) as RuntimeOptions;
|
const options = (msg.options || {}) as RuntimeOptions;
|
||||||
|
|
||||||
let boardDef = CURRENT_BOARD; //TODO: read from pxt.json/pxttarget.json
|
const boardDef = CURRENT_BOARD; //TODO: read from pxt.json/pxttarget.json
|
||||||
|
|
||||||
let cmpsList = msg.parts;
|
const cmpsList = msg.parts;
|
||||||
let cmpDefs = msg.partDefinitions || {}; //TODO: read from pxt.json/pxttarget.json
|
const cmpDefs = msg.partDefinitions || {}; //TODO: read from pxt.json/pxttarget.json
|
||||||
let fnArgs = msg.fnArgs;
|
const fnArgs = msg.fnArgs;
|
||||||
|
|
||||||
let viewHost = new visuals.BoardHost({
|
const opts : visuals.BoardHostOpts = {
|
||||||
state: this,
|
state: this,
|
||||||
boardDef: boardDef,
|
boardDef: boardDef,
|
||||||
partsList: cmpsList,
|
partsList: cmpsList,
|
||||||
@ -119,7 +82,8 @@ namespace pxsim {
|
|||||||
fnArgs: fnArgs,
|
fnArgs: fnArgs,
|
||||||
maxWidth: "100%",
|
maxWidth: "100%",
|
||||||
maxHeight: "100%",
|
maxHeight: "100%",
|
||||||
});
|
};
|
||||||
|
const viewHost = new visuals.BoardHost(pxsim.visuals.mkBoardView(opts), opts);
|
||||||
|
|
||||||
document.body.innerHTML = ""; // clear children
|
document.body.innerHTML = ""; // clear children
|
||||||
document.body.appendChild(viewHost.getView());
|
document.body.appendChild(viewHost.getView());
|
||||||
|
@ -354,8 +354,8 @@ namespace pxsim.instructions {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
function mkBlankBoardAndBreadboard(boardDef: BoardDefinition, cmpDefs: Map<PartDefinition>, fnArgs: any, width: number, buildMode: boolean = false): visuals.BoardHost {
|
function mkBlankBoardAndBreadboard(boardDef: BoardDefinition, cmpDefs: Map<PartDefinition>, fnArgs: any, width: number, buildMode: boolean = false): visuals.BoardHost {
|
||||||
let state = runtime.board as pxsim.CoreBoard;
|
const state = runtime.board as pxsim.CoreBoard;
|
||||||
let boardHost = new visuals.BoardHost({
|
const opts : visuals.BoardHostOpts = {
|
||||||
state: state,
|
state: state,
|
||||||
boardDef: boardDef,
|
boardDef: boardDef,
|
||||||
forceBreadboard: true,
|
forceBreadboard: true,
|
||||||
@ -363,7 +363,8 @@ namespace pxsim.instructions {
|
|||||||
maxWidth: `${width}px`,
|
maxWidth: `${width}px`,
|
||||||
fnArgs: fnArgs,
|
fnArgs: fnArgs,
|
||||||
wireframe: buildMode,
|
wireframe: buildMode,
|
||||||
});
|
};
|
||||||
|
let boardHost = new visuals.BoardHost(pxsim.visuals.mkBoardView(opts), opts);
|
||||||
let view = boardHost.getView();
|
let view = boardHost.getView();
|
||||||
svg.addClass(view, "board-svg");
|
svg.addClass(view, "board-svg");
|
||||||
|
|
||||||
|
@ -1,214 +0,0 @@
|
|||||||
namespace pxsim.visuals {
|
|
||||||
export interface BoardHostOpts {
|
|
||||||
state: CoreBoard,
|
|
||||||
boardDef: BoardDefinition,
|
|
||||||
partsList?: string[],
|
|
||||||
partDefs: Map<PartDefinition>,
|
|
||||||
fnArgs: any,
|
|
||||||
forceBreadboard?: boolean,
|
|
||||||
maxWidth?: string,
|
|
||||||
maxHeight?: string
|
|
||||||
wireframe?: boolean
|
|
||||||
}
|
|
||||||
export class BoardHost {
|
|
||||||
private parts: IBoardPart<any>[] = [];
|
|
||||||
private wireFactory: WireFactory;
|
|
||||||
private breadboard: Breadboard;
|
|
||||||
private fromBBCoord: (xy: Coord) => Coord;
|
|
||||||
private fromMBCoord: (xy: Coord) => Coord;
|
|
||||||
private boardView: BoardView;
|
|
||||||
private view: SVGSVGElement;
|
|
||||||
private partGroup: SVGGElement;
|
|
||||||
private partOverGroup: SVGGElement;
|
|
||||||
private style: SVGStyleElement;
|
|
||||||
private defs: SVGDefsElement;
|
|
||||||
private state: CoreBoard;
|
|
||||||
private useCrocClips: boolean;
|
|
||||||
|
|
||||||
constructor(opts: BoardHostOpts) {
|
|
||||||
this.state = opts.state;
|
|
||||||
let onboardCmps = opts.boardDef.onboardComponents || [];
|
|
||||||
let activeComponents = (opts.partsList || []).filter(c => onboardCmps.indexOf(c) < 0);
|
|
||||||
activeComponents.sort();
|
|
||||||
this.useCrocClips = opts.boardDef.useCrocClips;
|
|
||||||
|
|
||||||
if (opts.boardDef.visual === "microbit") {
|
|
||||||
this.boardView = new visuals.MicrobitBoardSvg({
|
|
||||||
runtime: runtime,
|
|
||||||
theme: visuals.randomTheme(),
|
|
||||||
disableTilt: false,
|
|
||||||
wireframe: opts.wireframe,
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
let boardVis = opts.boardDef.visual as BoardImageDefinition;
|
|
||||||
this.boardView = new visuals.GenericBoardSvg({
|
|
||||||
visualDef: boardVis,
|
|
||||||
wireframe: opts.wireframe,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
let useBreadboard = 0 < activeComponents.length || opts.forceBreadboard;
|
|
||||||
if (useBreadboard) {
|
|
||||||
this.breadboard = new Breadboard({
|
|
||||||
wireframe: opts.wireframe,
|
|
||||||
});
|
|
||||||
let bMarg = opts.boardDef.marginWhenBreadboarding || [0, 0, 40, 0];
|
|
||||||
let composition = composeSVG({
|
|
||||||
el1: this.boardView.getView(),
|
|
||||||
scaleUnit1: this.boardView.getPinDist(),
|
|
||||||
el2: this.breadboard.getSVGAndSize(),
|
|
||||||
scaleUnit2: this.breadboard.getPinDist(),
|
|
||||||
margin: [bMarg[0], bMarg[1], 20, bMarg[3]],
|
|
||||||
middleMargin: bMarg[2],
|
|
||||||
maxWidth: opts.maxWidth,
|
|
||||||
maxHeight: opts.maxHeight,
|
|
||||||
});
|
|
||||||
let under = composition.under;
|
|
||||||
let over = composition.over;
|
|
||||||
this.view = composition.host;
|
|
||||||
let edges = composition.edges;
|
|
||||||
this.fromMBCoord = composition.toHostCoord1;
|
|
||||||
this.fromBBCoord = composition.toHostCoord2;
|
|
||||||
let pinDist = composition.scaleUnit;
|
|
||||||
this.partGroup = over;
|
|
||||||
this.partOverGroup = <SVGGElement>svg.child(this.view, "g");
|
|
||||||
|
|
||||||
this.style = <SVGStyleElement>svg.child(this.view, "style", {});
|
|
||||||
this.defs = <SVGDefsElement>svg.child(this.view, "defs", {});
|
|
||||||
|
|
||||||
this.wireFactory = new WireFactory(under, over, edges, this.style, this.getLocCoord.bind(this));
|
|
||||||
|
|
||||||
let allocRes = allocateDefinitions({
|
|
||||||
boardDef: opts.boardDef,
|
|
||||||
partDefs: opts.partDefs,
|
|
||||||
fnArgs: opts.fnArgs,
|
|
||||||
getBBCoord: this.breadboard.getCoord.bind(this.breadboard),
|
|
||||||
partsList: activeComponents,
|
|
||||||
});
|
|
||||||
|
|
||||||
this.addAll(allocRes);
|
|
||||||
} else {
|
|
||||||
let el = this.boardView.getView().el;
|
|
||||||
this.view = el;
|
|
||||||
this.partGroup = <SVGGElement>svg.child(this.view, "g");
|
|
||||||
this.partOverGroup = <SVGGElement>svg.child(this.view, "g");
|
|
||||||
if (opts.maxWidth)
|
|
||||||
svg.hydrate(this.view, { width: opts.maxWidth });
|
|
||||||
if (opts.maxHeight)
|
|
||||||
svg.hydrate(this.view, { height: opts.maxHeight });
|
|
||||||
}
|
|
||||||
|
|
||||||
this.state.updateSubscribers.push(() => this.updateState());
|
|
||||||
}
|
|
||||||
|
|
||||||
public highlightBoardPin(pinNm: string) {
|
|
||||||
this.boardView.highlightPin(pinNm);
|
|
||||||
}
|
|
||||||
|
|
||||||
public highlightBreadboardPin(rowCol: BBLoc) {
|
|
||||||
this.breadboard.highlightLoc(rowCol);
|
|
||||||
}
|
|
||||||
|
|
||||||
public highlightWire(wire: Wire) {
|
|
||||||
//TODO: move to wiring.ts
|
|
||||||
//underboard wires
|
|
||||||
wire.wires.forEach(e => {
|
|
||||||
svg.addClass(e, "highlight");
|
|
||||||
(<any>e).style["visibility"] = "visible";
|
|
||||||
});
|
|
||||||
|
|
||||||
//un greyed out
|
|
||||||
svg.addClass(wire.endG, "highlight");
|
|
||||||
}
|
|
||||||
|
|
||||||
public getView(): SVGElement {
|
|
||||||
return this.view;
|
|
||||||
}
|
|
||||||
|
|
||||||
private updateState() {
|
|
||||||
this.parts.forEach(c => c.updateState());
|
|
||||||
}
|
|
||||||
|
|
||||||
private getBBCoord(rowCol: BBLoc) {
|
|
||||||
let bbCoord = this.breadboard.getCoord(rowCol);
|
|
||||||
return this.fromBBCoord(bbCoord);
|
|
||||||
}
|
|
||||||
private getPinCoord(pin: string) {
|
|
||||||
let boardCoord = this.boardView.getCoord(pin);
|
|
||||||
return this.fromMBCoord(boardCoord);
|
|
||||||
}
|
|
||||||
public getLocCoord(loc: Loc): Coord {
|
|
||||||
let coord: Coord;
|
|
||||||
if (loc.type === "breadboard") {
|
|
||||||
let rowCol = (<BBLoc>loc);
|
|
||||||
coord = this.getBBCoord(rowCol);
|
|
||||||
} else {
|
|
||||||
let pinNm = (<BoardLoc>loc).pin;
|
|
||||||
coord = this.getPinCoord(pinNm);
|
|
||||||
}
|
|
||||||
if (!coord) {
|
|
||||||
console.error("Unknown location: " + name)
|
|
||||||
return [0, 0];
|
|
||||||
}
|
|
||||||
return coord;
|
|
||||||
}
|
|
||||||
|
|
||||||
public addPart(partInst: PartInst): IBoardPart<any> {
|
|
||||||
let part: IBoardPart<any> = null;
|
|
||||||
let colOffset = 0;
|
|
||||||
if (partInst.simulationBehavior) {
|
|
||||||
//TODO: seperate simulation behavior from builtin visual
|
|
||||||
let builtinBehavior = partInst.simulationBehavior;
|
|
||||||
let cnstr = this.state.builtinVisuals[builtinBehavior];
|
|
||||||
let stateFn = this.state.builtinParts[builtinBehavior];
|
|
||||||
part = cnstr();
|
|
||||||
part.init(this.state.bus, stateFn, this.view, partInst.params);
|
|
||||||
} else {
|
|
||||||
let vis = partInst.visual as PartVisualDefinition;
|
|
||||||
part = new GenericPart(vis);
|
|
||||||
}
|
|
||||||
this.parts.push(part);
|
|
||||||
this.partGroup.appendChild(part.element);
|
|
||||||
if (part.overElement)
|
|
||||||
this.partOverGroup.appendChild(part.overElement);
|
|
||||||
if (part.defs)
|
|
||||||
part.defs.forEach(d => this.defs.appendChild(d));
|
|
||||||
this.style.textContent += part.style || "";
|
|
||||||
let colIdx = partInst.startColumnIdx;
|
|
||||||
let rowIdx = partInst.startRowIdx;
|
|
||||||
let row = getRowName(rowIdx);
|
|
||||||
let col = getColumnName(colIdx);
|
|
||||||
let xOffset = partInst.bbFit.xOffset / partInst.visual.pinDistance;
|
|
||||||
let yOffset = partInst.bbFit.yOffset / partInst.visual.pinDistance;
|
|
||||||
let rowCol = <BBLoc>{
|
|
||||||
type: "breadboard",
|
|
||||||
row: row,
|
|
||||||
col: col,
|
|
||||||
xOffset: xOffset,
|
|
||||||
yOffset: yOffset
|
|
||||||
};
|
|
||||||
let coord = this.getBBCoord(rowCol);
|
|
||||||
part.moveToCoord(coord);
|
|
||||||
let getCmpClass = (type: string) => `sim-${type}-cmp`;
|
|
||||||
let cls = getCmpClass(partInst.name);
|
|
||||||
svg.addClass(part.element, cls);
|
|
||||||
svg.addClass(part.element, "sim-cmp");
|
|
||||||
part.updateTheme();
|
|
||||||
part.updateState();
|
|
||||||
return part;
|
|
||||||
}
|
|
||||||
public addWire(inst: WireInst): Wire {
|
|
||||||
return this.wireFactory.addWire(inst.start, inst.end, inst.color, this.useCrocClips);
|
|
||||||
}
|
|
||||||
public addAll(allocRes: AllocatorResult) {
|
|
||||||
allocRes.partsAndWires.forEach(pAndWs => {
|
|
||||||
let part = pAndWs.part;
|
|
||||||
if (part)
|
|
||||||
this.addPart(part)
|
|
||||||
let wires = pAndWs.wires;
|
|
||||||
if (wires)
|
|
||||||
wires.forEach(w => this.addWire(w));
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
19
sim/visuals/boardview.ts
Normal file
19
sim/visuals/boardview.ts
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
namespace pxsim.visuals {
|
||||||
|
export function mkBoardView(opts: BoardHostOpts): BoardView {
|
||||||
|
if (opts.boardDef.visual === "microbit") {
|
||||||
|
return new visuals.MicrobitBoardSvg({
|
||||||
|
runtime: runtime,
|
||||||
|
theme: visuals.randomTheme(),
|
||||||
|
disableTilt: false,
|
||||||
|
wireframe: opts.wireframe,
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
let boardVis = opts.boardDef.visual as BoardImageDefinition;
|
||||||
|
return new visuals.GenericBoardSvg({
|
||||||
|
visualDef: boardVis,
|
||||||
|
wireframe: opts.wireframe,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user