mirror of
https://github.com/whscullin/apple2js.git
synced 2024-01-12 14:14:38 +00:00
parent
f28641df32
commit
66d8fdc2c2
3
.github/workflows/nodejs.yml
vendored
3
.github/workflows/nodejs.yml
vendored
@ -17,9 +17,6 @@ jobs:
|
|||||||
uses: actions/setup-node@v1
|
uses: actions/setup-node@v1
|
||||||
with:
|
with:
|
||||||
node-version: ${{ matrix.node-version }}
|
node-version: ${{ matrix.node-version }}
|
||||||
- uses: webfactory/ssh-agent@v0.5.0
|
|
||||||
with:
|
|
||||||
ssh-private-key: ${{ secrets.SSH_PRIVATE_KEY }}
|
|
||||||
- name: npm install, build, and test
|
- name: npm install, build, and test
|
||||||
run: |
|
run: |
|
||||||
npm ci
|
npm ci
|
||||||
|
@ -240,11 +240,15 @@
|
|||||||
</table>
|
</table>
|
||||||
<form action="#">
|
<form action="#">
|
||||||
<input type="file" id="local_file" />
|
<input type="file" id="local_file" />
|
||||||
|
<div id="local_file_address_input" style="display: none">
|
||||||
|
$
|
||||||
|
<input id="local_file_address" />
|
||||||
|
</div>
|
||||||
</form>
|
</form>
|
||||||
</main>
|
</main>
|
||||||
<footer class="modal__footer">
|
<footer class="modal__footer">
|
||||||
<button class="modal__btn" data-micromodal-close aria-label="Close this dialog window">Cancel</button>
|
<button class="modal__btn" data-micromodal-close aria-label="Close this dialog window">Cancel</button>
|
||||||
<button class="modal__btn" onclick="Apple2.doLoad()" aria-label="Open the selected disk">Open</button>
|
<button class="modal__btn" onclick="Apple2.doLoad(event)" aria-label="Open the selected disk">Open</button>
|
||||||
</footer>
|
</footer>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
@ -249,11 +249,15 @@
|
|||||||
</table>
|
</table>
|
||||||
<form action="#">
|
<form action="#">
|
||||||
<input type="file" id="local_file" />
|
<input type="file" id="local_file" />
|
||||||
|
<div id="local_file_address_input" style="display: none">
|
||||||
|
$
|
||||||
|
<input id="local_file_address" />
|
||||||
|
</div>
|
||||||
</form>
|
</form>
|
||||||
</main>
|
</main>
|
||||||
<footer class="modal__footer">
|
<footer class="modal__footer">
|
||||||
<button class="modal__btn" data-micromodal-close aria-label="Close this dialog window">Cancel</button>
|
<button class="modal__btn" data-micromodal-close aria-label="Close this dialog window">Cancel</button>
|
||||||
<button class="modal__btn" onclick="Apple2.doLoad()" aria-label="Open the selected disk">Open</button>
|
<button class="modal__btn" onclick="Apple2.doLoad(event)" aria-label="Open the selected disk">Open</button>
|
||||||
</footer>
|
</footer>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
15
js/gl.ts
15
js/gl.ts
@ -517,6 +517,8 @@ export class HiresPageGL implements HiresPage {
|
|||||||
}
|
}
|
||||||
} else if (bank === 0) {
|
} else if (bank === 0) {
|
||||||
const hbs = val & 0x80;
|
const hbs = val & 0x80;
|
||||||
|
const lastCol = col === 39;
|
||||||
|
const cropLastPixel = hbs && lastCol;
|
||||||
const dx = col * 14;
|
const dx = col * 14;
|
||||||
let offset = dx * 4 + dy * 560 * 4;
|
let offset = dx * 4 + dy * 560 * 4;
|
||||||
if (hbs) {
|
if (hbs) {
|
||||||
@ -530,22 +532,25 @@ export class HiresPageGL implements HiresPage {
|
|||||||
}
|
}
|
||||||
let bits = val;
|
let bits = val;
|
||||||
for (let idx = 0; idx < 7; idx++, offset += 8) {
|
for (let idx = 0; idx < 7; idx++, offset += 8) {
|
||||||
|
const drawPixel = cropLastPixel && idx == 6
|
||||||
|
? this._drawHalfPixel
|
||||||
|
: this._drawPixel;
|
||||||
if (bits & 0x01) {
|
if (bits & 0x01) {
|
||||||
this._drawPixel(data, offset, whiteCol);
|
drawPixel(data, offset, whiteCol);
|
||||||
} else {
|
} else {
|
||||||
this._drawPixel(data, offset, blackCol);
|
drawPixel(data, offset, blackCol);
|
||||||
}
|
}
|
||||||
bits >>= 1;
|
bits >>= 1;
|
||||||
}
|
}
|
||||||
}
|
if (!this._refreshing) {
|
||||||
}
|
|
||||||
if (!this._refreshing && !doubleHiresMode && bank === 0) {
|
|
||||||
this._refreshing = true;
|
this._refreshing = true;
|
||||||
const after = addr + 1;
|
const after = addr + 1;
|
||||||
this._write(after >> 8, after & 0xff, this._buffer[0][after & 0x1fff], 0);
|
this._write(after >> 8, after & 0xff, this._buffer[0][after & 0x1fff], 0);
|
||||||
this._refreshing = false;
|
this._refreshing = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
refresh() {
|
refresh() {
|
||||||
let addr = 0x2000 * this.page;
|
let addr = 0x2000 * this.page;
|
||||||
|
@ -49,6 +49,8 @@ type DiskCollection = {
|
|||||||
[name: string]: DiskDescriptor[]
|
[name: string]: DiskDescriptor[]
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const KNOWN_FILE_TYPES = [...DISK_FORMATS, ...TAPE_TYPES] as readonly string[];
|
||||||
|
|
||||||
const disk_categories: DiskCollection = { 'Local Saves': [] };
|
const disk_categories: DiskCollection = { 'Local Saves': [] };
|
||||||
const disk_sets: DiskCollection = {};
|
const disk_sets: DiskCollection = {};
|
||||||
// Disk names
|
// Disk names
|
||||||
@ -239,7 +241,7 @@ export function loadAjax(drive: DriveNumber, url: string) {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
export function doLoad() {
|
export function doLoad(event: MouseEvent|KeyboardEvent) {
|
||||||
MicroModal.close('load-modal');
|
MicroModal.close('load-modal');
|
||||||
const select = document.querySelector<HTMLSelectElement>('#disk_select')!;
|
const select = document.querySelector<HTMLSelectElement>('#disk_select')!;
|
||||||
const urls = select.value;
|
const urls = select.value;
|
||||||
@ -255,7 +257,8 @@ export function doLoad() {
|
|||||||
const localFile = document.querySelector<HTMLInputElement>('#local_file')!;
|
const localFile = document.querySelector<HTMLInputElement>('#local_file')!;
|
||||||
const files = localFile.files;
|
const files = localFile.files;
|
||||||
if (files && files.length == 1) {
|
if (files && files.length == 1) {
|
||||||
doLoadLocal(_currentDrive, files[0]);
|
const runOnLoad = event.shiftKey;
|
||||||
|
doLoadLocal(_currentDrive, files[0], { runOnLoad });
|
||||||
} else if (url) {
|
} else if (url) {
|
||||||
let filename;
|
let filename;
|
||||||
MicroModal.close('load-modal');
|
MicroModal.close('load-modal');
|
||||||
@ -316,10 +319,21 @@ function doLoadLocal(drive: DriveNumber, file: File, options: Partial<LoadOption
|
|||||||
tape.doLoadLocalTape(file);
|
tape.doLoadLocalTape(file);
|
||||||
} else if (BIN_TYPES.includes(ext) || type === '06' || options.address) {
|
} else if (BIN_TYPES.includes(ext) || type === '06' || options.address) {
|
||||||
doLoadBinary(file, { address: parseInt(aux || '2000', 16), ...options });
|
doLoadBinary(file, { address: parseInt(aux || '2000', 16), ...options });
|
||||||
|
} else {
|
||||||
|
const addressInput = document.querySelector<HTMLInputElement>('#local_file_address');
|
||||||
|
const addressStr = addressInput?.value;
|
||||||
|
if (addressStr) {
|
||||||
|
const address = parseInt(addressStr, 16);
|
||||||
|
if (isNaN(address)) {
|
||||||
|
openAlert('Invalid address: ' + addressStr);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
doLoadBinary(file, { address, ...options });
|
||||||
} else {
|
} else {
|
||||||
openAlert('Unknown file type: ' + ext);
|
openAlert('Unknown file type: ' + ext);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
function doLoadBinary(file: File, options: LoadOptions) {
|
function doLoadBinary(file: File, options: LoadOptions) {
|
||||||
loadingStart();
|
loadingStart();
|
||||||
@ -523,7 +537,8 @@ export function reset() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function loadBinary(bin: JSONBinaryImage) {
|
function loadBinary(bin: JSONBinaryImage) {
|
||||||
for (let idx = 0; idx < bin.length; idx++) {
|
const maxLen = Math.min(bin.length, 0x10000 - bin.start);
|
||||||
|
for (let idx = 0; idx < maxLen; idx++) {
|
||||||
const pos = bin.start + idx;
|
const pos = bin.start + idx;
|
||||||
cpu.write(pos, bin.data[idx]);
|
cpu.write(pos, bin.data[idx]);
|
||||||
}
|
}
|
||||||
@ -559,8 +574,8 @@ export function selectDisk() {
|
|||||||
localFile.value = '';
|
localFile.value = '';
|
||||||
}
|
}
|
||||||
|
|
||||||
export function clickDisk() {
|
export function clickDisk(event: MouseEvent|KeyboardEvent) {
|
||||||
doLoad();
|
doLoad(event);
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Called to load disks from the local catalog. */
|
/** Called to load disks from the local catalog. */
|
||||||
@ -854,6 +869,22 @@ function onLoaded(apple2: Apple2, disk2: DiskII, smartPort: SmartPort, printer:
|
|||||||
_apple2.run();
|
_apple2.run();
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
document.querySelector<HTMLInputElement>('#local_file')?.addEventListener(
|
||||||
|
'change',
|
||||||
|
(event: Event) => {
|
||||||
|
const target = event.target as HTMLInputElement;
|
||||||
|
const address = document.querySelector<HTMLInputElement>('#local_file_address_input')!;
|
||||||
|
const parts = target.value.split('.');
|
||||||
|
const ext = parts[parts.length - 1];
|
||||||
|
|
||||||
|
if (KNOWN_FILE_TYPES.includes(ext)) {
|
||||||
|
address.style.display = 'none';
|
||||||
|
} else {
|
||||||
|
address.style.display = 'inline-block';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
export function initUI(apple2: Apple2, disk2: DiskII, smartPort: SmartPort, printer: Printer, e: boolean) {
|
export function initUI(apple2: Apple2, disk2: DiskII, smartPort: SmartPort, printer: Printer, e: boolean) {
|
||||||
|
Loading…
Reference in New Issue
Block a user