Compare commits

...

4 Commits

Author SHA1 Message Date
Christopher A. Mosher e0f4ad5ccc more legacy command line code cleanup 2022-12-13 00:03:26 -05:00
Christopher A. Mosher 7bab1ac971 remove ability to show screen as 'scan lines' (i.e., always fill, aka bleed down) 2022-12-12 23:57:16 -05:00
Christopher A. Mosher 027248a002 remove hyper setting 2022-12-12 23:30:24 -05:00
Christopher A. Mosher a5c0fc047e change command line entry from home-grown SDL to standard wx text dlg input 2022-12-12 22:34:13 -05:00
19 changed files with 62 additions and 274 deletions

View File

@ -89,7 +89,6 @@ filterchroma.cpp
filterluma.cpp
firmwarecard.cpp
gui.cpp
hypermode.cpp
keyboardbuffermode.cpp
keyboard.cpp
languagecard.cpp

View File

@ -28,7 +28,7 @@
#include "e2const.h"
#include <wx/app.h>
#include <wx/uiaction.h>
#include <wx/textdlg.h>
#include <wx/window.h>
#include <wx/xrc/xmlres.h>
#include <wx/fileconf.h>
@ -151,6 +151,10 @@ bool E2wxApp::OnInit() {
// wxLogVerbose("%s", "verbose");
// wxFile().Open("foobar.txt");
// TODO wx log file window?
// TODO remove all logging from stdout/err to log file
// TODO define components to turn on/off for trace level logging (disk, cassette, woz, keyboard, ram, lss, audio, etc.)
BOOST_LOG_TRIVIAL(info) << "Application ID: " << this->GetID();
BOOST_LOG_TRIVIAL(info) << "Application version: " << this->GetVersion();
@ -213,7 +217,7 @@ void E2wxApp::OnFnKeyPressed(const SDL_Keycode k) {
} else if (k == SDLK_F4) {
//
} else if (k == SDLK_F5) {
//
this->EmulatorCommand();
} else if (k == SDLK_F6) {
this->Reset();
} else if (k == SDLK_F7) {
@ -446,3 +450,14 @@ void E2wxApp::ToggleFullScreen() {
this->emu->toggleFullScreen();
}
}
static const wxString message = "Enter a command for the emulator. See https://cmosher01.github.io/Epple-II/usermanual.html";
static const wxString title = "Emulator command";
void E2wxApp::EmulatorCommand() {
if (this->emu) {
wxTextEntryDialog dlg(this->frame, message, title);
if (dlg.ShowModal() == wxID_OK) {
this->emu->cmd(dlg.GetValue());
}
}
}

View File

@ -95,6 +95,7 @@ public:
void TogglePower();
void ToggleBuffered();
void ToggleFullScreen();
void EmulatorCommand();
virtual bool OnInit() override;
virtual int OnExit() override;

View File

@ -33,6 +33,7 @@ enum E2MenuID {
ID_MENUITEM_POWER = wxID_HIGHEST+1,
ID_MENUITEM_CYCLE_MONITOR,
ID_MENUITEM_TOGGLE_FULL_SCREEN,
ID_MENUITEM_EMULATOR_COMMAND,
ID_MENUITEM_RESET,
ID_MENUITEM_SCREEN_SHOT,
ID_MENUITEM_TOGGLE_BUFFERED,
@ -46,6 +47,7 @@ wxBEGIN_EVENT_TABLE(E2wxFrame, wxFrame)
EVT_MENU(ID_MENUITEM_POWER, E2wxFrame::OnTogglePower)
EVT_MENU(ID_MENUITEM_CYCLE_MONITOR, E2wxFrame::OnCycleMonitor)
EVT_MENU(ID_MENUITEM_TOGGLE_FULL_SCREEN, E2wxFrame::OnToggleFullScreen)
EVT_MENU(ID_MENUITEM_EMULATOR_COMMAND, E2wxFrame::OnEmulatorCommand)
EVT_MENU(ID_MENUITEM_RESET, E2wxFrame::OnReset)
EVT_MENU(wxID_PASTE, E2wxFrame::OnPaste)
EVT_MENU(ID_MENUITEM_SCREEN_SHOT, E2wxFrame::OnScreenShot)
@ -97,6 +99,9 @@ void E2wxFrame::InitMenuBar() {
wxMenuItem *miReset = menuMachine->Append(ID_MENUITEM_RESET, "Reset");
miReset->SetAccel(new wxAcceleratorEntry(wxACCEL_NORMAL, WXK_F6));
menuMachine->AppendSeparator();
wxMenuItem *miCmd = menuMachine->Append(ID_MENUITEM_EMULATOR_COMMAND, "Command...");
miCmd->SetAccel(new wxAcceleratorEntry(wxACCEL_NORMAL, WXK_F5));
menuMachine->AppendSeparator();
wxMenuItem *miBuffered = menuMachine->Append(ID_MENUITEM_TOGGLE_BUFFERED, "Toggle Keyboard Buffer");
miBuffered->SetAccel(new wxAcceleratorEntry(wxACCEL_NORMAL, WXK_F12));
@ -170,6 +175,10 @@ void E2wxFrame::OnToggleFullScreen(wxCommandEvent& event) {
wxGetApp().ToggleFullScreen();
}
void E2wxFrame::OnEmulatorCommand(wxCommandEvent& event) {
wxGetApp().EmulatorCommand();
}
void E2wxFrame::OnReset(wxCommandEvent& event) {
wxGetApp().Reset();
}
@ -185,5 +194,3 @@ void E2wxFrame::OnScreenShot(wxCommandEvent& event) {
void E2wxFrame::OnToggleBuffered(wxCommandEvent& event) {
wxGetApp().ToggleBuffered();
}

View File

@ -45,6 +45,7 @@ private:
void OnTogglePower(wxCommandEvent& event);
void OnCycleMonitor(wxCommandEvent& event);
void OnToggleFullScreen(wxCommandEvent& event);
void OnEmulatorCommand(wxCommandEvent& event);
void OnReset(wxCommandEvent& event);
void OnPaste(wxCommandEvent& event);
void OnScreenShot(wxCommandEvent& event);

View File

@ -44,8 +44,7 @@ AnalogTV::AnalogTV(ScreenImage& image):
image(image),
on(false),
noise(false),
type(TV_OLD_COLOR),
bleed_down(true)
type(TV_OLD_COLOR)
{
hirescolor.push_back(colors.c()[A2ColorsObserved::HIRES_GREEN]);
hirescolor.push_back(colors.c()[A2ColorsObserved::HIRES_ORANGE]);
@ -84,13 +83,6 @@ void AnalogTV::cycleType()
this->type = (DisplayType)((((int)this->type)+1)%NUM_DISPLAY_TYPES);
}
void AnalogTV::toggleBleedDown()
{
this->bleed_down = !this->bleed_down;
this->image.blank();
this->image.notifyObservers();
}
@ -268,8 +260,7 @@ void AnalogTV::drawMonitorColor()
rgbv = 0xFFFFFF;
}
this->image.setElem(ip,rgbv);
if (bleed_down)
this->image.setElem(ip+D_IP,rgbv); // display same pixel on next row
this->image.setElem(ip+D_IP,rgbv); // display same pixel on next row
++ip;
}
ip += D_IP;
@ -292,8 +283,7 @@ void AnalogTV::drawMonitorMonochrome(const unsigned int color)
const int is = row*AppleNTSC::H+col;
const unsigned int rgb = this->signal[is] > 50 ? color : 0;
this->image.setElem(ip,rgb);
if (bleed_down)
this->image.setElem(ip+D_IP,rgb);
this->image.setElem(ip+D_IP,rgb);
++ip;
}
ip += D_IP;
@ -314,8 +304,7 @@ void AnalogTV::drawTVOld()
{
const int rgb = yiq2rgb(yiq[col-348]); // shift display left 1 pixel
this->image.setElem(ip,rgb);
if (bleed_down)
this->image.setElem(ip+D_IP,rgb);
this->image.setElem(ip+D_IP,rgb);
++ip;
}
ip += D_IP;

View File

@ -46,7 +46,6 @@ private:
bool on;
bool noise;
DisplayType type;
bool bleed_down;
static int* rcb;
@ -95,7 +94,6 @@ public:
}
void powerOn(bool b);
void toggleBleedDown();
void restartSignal();
void setType(DisplayType type);
void cycleType();

View File

@ -38,9 +38,9 @@
#include <istream>
#include <fstream>
Apple2::Apple2(KeypressQueue& keypresses, PaddleButtonStates& paddleButtonStates, AnalogTV& tv, HyperMode& fhyper, KeyboardBufferMode& buffered, ScreenImage& gui) :
Apple2::Apple2(KeypressQueue& keypresses, PaddleButtonStates& paddleButtonStates, AnalogTV& tv, KeyboardBufferMode& buffered, ScreenImage& gui) :
slts(gui),
kbd(keypresses, fhyper, buffered),
kbd(keypresses, buffered),
rom(AddressBus::MOTHERBOARD_ROM_SIZ),
ram(revision),
cassetteIn(gui),

View File

@ -63,7 +63,7 @@ class Apple2 : public Timable
int revision;
public:
Apple2(KeypressQueue& keypresses, PaddleButtonStates& paddleButtonStates, AnalogTV& tv, HyperMode& fhyper, KeyboardBufferMode& buffered, ScreenImage& gui);
Apple2(KeypressQueue& keypresses, PaddleButtonStates& paddleButtonStates, AnalogTV& tv, KeyboardBufferMode& buffered, ScreenImage& gui);
~Apple2();
void useEpple2Cpu();

View File

@ -326,7 +326,6 @@ void E2Command::tryParseLine(const std::string& line, MemoryRandomAccess& ram, M
void E2Command::loadDisk(Slots& slts, int slot, int drive, const std::filesystem::path &media) {
Card* card = slts.get(slot);
if (!card->hasMedia()) {
// TODO if file doesn't exist, name still gets displayed, and there's no error message
// TODO error message
// std::cerr << "Slot " << slot << " doesn't have a disk controller card" << std::endl;
return;

View File

@ -18,9 +18,12 @@
#ifndef CONFIGEP2_H
#define CONFIGEP2_H
#include <wx/string.h>
#include <filesystem>
#include <string>
class Memory;
class MemoryRandomAccess;
class Slots;
@ -30,9 +33,7 @@ class CassetteOut;
class Apple2;
// TODO split out all static things into their own class (and don't make them static)
// Remember that, besides config, also command line entry calls parseLine
// This will also help with adding menu items in place of commands
class E2Config {
private:
const std::filesystem::path file_path;
@ -50,4 +51,6 @@ public:
void parse(MemoryRandomAccess& ram, Memory& rom, Slots& slts, int& revision, ScreenImage& gui, CassetteIn& cassetteIn, CassetteOut& cassetteOut, Apple2* apple2);
};
#endif

View File

@ -47,13 +47,11 @@ static bool isKeyDown(const SDL_Keycode sym, const SDL_Keymod mod) {
Emulator::Emulator() :
display(screenImage),
videoStatic(display),
apple2(keypresses, paddleButtonStates, display, fhyper, buffered, screenImage),
apple2(keypresses, paddleButtonStates, display, buffered, screenImage),
timable(nullptr), // No ticked object (NULL pointer)
repeat(false),
keysDown(0),
prev_ms(SDL_GetTicks()),
command(false),
pendingCommandExit(false) {
prev_ms(SDL_GetTicks()) {
}
Emulator::~Emulator() {
@ -106,29 +104,13 @@ void Emulator::handleAnyPendingEvents() {
wxGetApp().CloseMainFrame();
break;
case SDL_KEYDOWN:
// If we're collecting a command line for changing any
// of the configurables of the emulator...
if (this->command)
cmdKey(event.key);
else
// ...else we're collecting keypresses for the keyboard
// emulation (and thus the Apple ][ emulation itself)
dispatchKeyDown(event.key);
// People who have too many press-releases should be referred to as "keyboards"
// we're collecting keypresses for the keyboard
// emulation (and thus the Apple ][ emulation itself)
dispatchKeyDown(event.key);
// People who have too many press-releases should be referred to as "keyboards"
break;
case SDL_KEYUP:
// If we're collecting a command line for changing any
// of the configurables of the emulator...
if (this->command) {
if (this->pendingCommandExit) {
this->command = false;
this->pendingCommandExit = false;
}
} else {
// ...else we're collecting keypresses for the keyboard
// emulation (and thus the Apple ][ emulation itself)
dispatchKeyUp(event.key);
}
dispatchKeyUp(event.key);
break;
}
}
@ -234,7 +216,6 @@ static bool translateKeysToAppleModernized(SDL_Keycode keycode, SDL_Keymod modif
return false;
}
return true;
}
@ -258,10 +239,6 @@ void Emulator::dispatchKeyDown(const SDL_KeyboardEvent& keyEvent) {
this->repeat = true;
this->rept = CYCLES_PER_REPT;
return;
} else if (sym == SDLK_F5) { // TODO re-do user-entered command line
this->command = true;
this->screenImage.enterCommandMode();
return;
} else if (SDLK_F1 <= sym && sym <= SDLK_F12) {
wxGetApp().OnFnKeyPressed(sym);
return;
@ -295,63 +272,19 @@ void Emulator::dispatchKeyUp(const SDL_KeyboardEvent& keyEvent) {
// TODO redo command line handling
// Collect and edit a command line typed at the bottom of the emulator window
void Emulator::cmdKey(const SDL_KeyboardEvent& keyEvent) {
SDL_Keycode sym = keyEvent.keysym.sym;
unsigned char key = (unsigned char) (sym & 0x7F);
if (sym == SDLK_RETURN) {
processCommand();
} else if (sym == SDLK_ESCAPE) {
cmdline.erase(cmdline.begin(), cmdline.end());
processCommand();
} else if (sym == SDLK_BACKSPACE) {
if (cmdline.length()) {
cmdline.erase(cmdline.end() - 1);
this->screenImage.backspaceCommand();
}
} else if (sym == SDLK_INSERT) {
std::string s = this->clip.getText();
for (unsigned int i = 0; i < s.length(); ++i) {
key = s[i];
if (key == '\n' || key == '\r') {
processCommand();
break;
} else {
cmdline += key;
this->screenImage.addkeyCommand(key);
}
}
} else if (key) {
cmdline += key;
this->screenImage.addkeyCommand(key);
}
}
// Process a command line typed at the bottom of the emulator window
void Emulator::processCommand() {
this->screenImage.exitCommandMode();
this->screenImage.drawPower(this->timable == &this->apple2);
this->pendingCommandExit = true;
if (cmdline.empty()) {
void Emulator::cmd(const wxString& c) {
if (c.empty()) {
return;
}
E2Command{}.parseLine(cmdline, this->apple2.ram, this->apple2.rom, this->apple2.slts, this->apple2.revision, this->screenImage, this->apple2.cassetteIn, this->apple2.cassetteOut, NULL);
cmdline.erase(cmdline.begin(), cmdline.end());
E2Command{}.parseLine(
c.c_str().AsChar(),
this->apple2.ram, this->apple2.rom, this->apple2.slts, this->apple2.revision, this->screenImage, this->apple2.cassetteIn, this->apple2.cassetteOut, nullptr);
}
static int askSave() {
wxMessageDialog *dlg = new wxMessageDialog{
nullptr,

View File

@ -25,9 +25,9 @@
#include "screenimage.h"
#include "analogtv.h"
#include "keyboardbuffermode.h"
#include "hypermode.h"
#include "clipboardhandler.h"
#include <SDL.h>
#include <wx/string.h>
class Timable;
class E2Config;
@ -36,7 +36,6 @@ class Emulator {
PaddleButtonStates paddleButtonStates;
KeypressQueue keypresses;
HyperMode fhyper;
KeyboardBufferMode buffered;
ScreenImage screenImage;
AnalogTV display;
@ -51,14 +50,9 @@ class Emulator {
int rept;
unsigned char lastKeyDown;
Uint32 prev_ms;
bool command;
bool pendingCommandExit;
std::string cmdline;
void dispatchKeyDown(const SDL_KeyboardEvent& keyEvent);
void dispatchKeyUp(const SDL_KeyboardEvent& keyEvent);
void cmdKey(const SDL_KeyboardEvent& keyEvent);
void processCommand();
void powerOnComputer();
void powerOffComputer();
@ -71,6 +65,7 @@ public:
void config(E2Config& cfg);
void tick50ms();
void cmd(const wxString& c);
bool isSafeToQuit();
void toggleComputerPower();

View File

@ -1,18 +0,0 @@
/*
epple2
Copyright (C) 2008 by Christopher A. Mosher <cmosher01@gmail.com>
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY, without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "hypermode.h"

View File

@ -1,45 +0,0 @@
/*
epple2
Copyright (C) 2008 by Christopher A. Mosher <cmosher01@gmail.com>
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY, without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef HYPERMODE_H
#define HYPERMODE_H
class HyperMode
{
private:
bool fhyper;
public:
HyperMode(): fhyper(false) { }
~HyperMode() { }
bool isHyper()
{
return this->fhyper;
}
void setHyper(bool isHyper)
{
this->fhyper = isHyper;
}
void toggleHyper()
{
this->fhyper = !this->fhyper;
}
};
#endif

View File

@ -16,15 +16,13 @@
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "keyboard.h"
#include "hypermode.h"
#include "keyboardbuffermode.h"
#include <cstdlib>
Keyboard::Keyboard(KeypressQueue& q, HyperMode& fhyper, KeyboardBufferMode& buffered) :
Keyboard::Keyboard(KeypressQueue& q, KeyboardBufferMode& buffered) :
keys(q),
fhyper(fhyper),
buffered(buffered),
latch(0),
cGet(0) {
@ -39,7 +37,6 @@ void Keyboard::clear() {
}
unsigned char Keyboard::get() {
waitIfTooFast();
if (!this->buffered.isBuffered() || !(this->latch & 0x80)) {
if (!this->keys.empty()) {
this->latch = this->keys.front() | 0x80;
@ -48,28 +45,3 @@ unsigned char Keyboard::get() {
}
return this->latch;
}
void Keyboard::waitIfTooFast() {
// TODO remove all hyper stuff; it doesn't do anything anymore,
// since the new architecture with wxTimer
// if (this->fhyper.isHyper()) {
// return;
// }
//
// ++this->cGet;
// if (!this->cGet) {
// if (SDL_GetTicks() - this->lastGet <= 1000) {
// /*
// * Check every 256 gets to see if they are
// * happening too fast (within one second).
// * If so, it means we are probably just
// * looping waiting for a keypress, so
// * wait a millisecond (or so) just to
// * prevent us from using 100% of CPU time.
// */
// SDL_Delay(1);
// }
// }
// this->lastGet = SDL_GetTicks();
}

View File

@ -23,22 +23,18 @@
typedef std::queue<unsigned char> KeypressQueue;
class HyperMode;
class KeyboardBufferMode;
class Keyboard {
KeypressQueue& keys;
HyperMode& fhyper;
KeyboardBufferMode& buffered;
unsigned char latch;
unsigned char cGet;
Uint32 lastGet;
void waitIfTooFast();
public:
Keyboard(KeypressQueue& q, HyperMode& fhyper, KeyboardBufferMode& buffered);
Keyboard(KeypressQueue& q, KeyboardBufferMode& buffered);
void powerOn();
void clear();
unsigned char get();

View File

@ -28,6 +28,8 @@
#include <cstdio>
#include <cstring>
// TODO For screen image in general, remove items from this SDL window to the wx frame as appropriate
static const char* power =
" @@@@ @@@ @ @ @ @@@@@ @@@@ "
" @ @ @ @ @ @ @ @ @ @ @"
@ -56,9 +58,7 @@ class ScreenException {
ScreenImage::ScreenImage() :
fullscreen(false),
hyper_a2_speed(false),
buffer(true),
fillLines(true),
display(AnalogTV::TV_OLD_COLOR),
slotnames(8),
cassInName(32, ' '),
@ -165,37 +165,23 @@ void ScreenImage::drawFnKeys() {
int r(76);
int c(1);
drawText(
" FULLSCRN SCAN-LINES KEYBOARD", r++, c);
" FULLSCRN KEYBOARD", r++, c);
drawText(
" XXXXXXXXXXXXXX WINDOW FILL-LINES CMD RESET PASTE SAVE BMP QUIT! REPT HYPER BUFFER ", r++, c);
" XXXXXXXXXXXXXX WINDOW CMD RESET PASTE SAVE BMP QUIT! REPT BUFFER ", r++, c);
drawText(
" F1 F2 F3 F4 F5 F6 F7 F8 F9 F10 F11 F12 ", r++, c);
" F1 F2 F3 F5 F6 F7 F8 F9 F10 F12 ", r++, c);
if (this->fullscreen)
invertText(76, 32, 42); // FULLSCRN
else
invertText(77, 32, 40); // WINDOW
if (this->fillLines)
invertText(77, 43, 55); // FILL-LINES
else
invertText(76, 43, 55); // SCAN-LINES
if (this->hyper_a2_speed)
invertText(77, 102, 109); // HYPER
if (this->buffer)
invertText(77, 110, 118); // BUFFER
drawDisplayLabel();
}
void ScreenImage::toggleFillLinesLabel() {
this->fillLines = !this->fillLines;
invertText(76, 43, 55); // SCAN-LINES
invertText(77, 43, 55); // FILL-LINES
}
void ScreenImage::drawDisplayLabel() {
const char* label = displays[(int) (this->display)];
drawText(label, 77, 17);
@ -206,11 +192,6 @@ void ScreenImage::cycleDisplayLabel() {
drawDisplayLabel();
}
void ScreenImage::toggleHyperLabel() {
this->hyper_a2_speed = !this->hyper_a2_speed;
invertText(77, 102, 109); // HYPER
}
void ScreenImage::toggleKdbBufferLabel() {
this->buffer = !this->buffer;
invertText(77, 110, 118); // BUFFER
@ -320,35 +301,6 @@ void ScreenImage::blank() {
}
}
void ScreenImage::enterCommandMode() {
int r(76);
int c(1);
unsigned int* pn = this->pixels;
pn += r * FONTH * SCRW + c*FONTW;
memset((char*) pn, 0, SCRW * 4 * FONTH * 3);
drawText("command: ", 78, 1);
this->cmdpos = 9;
notifyObservers();
}
void ScreenImage::exitCommandMode() {
drawFnKeys();
notifyObservers();
}
void ScreenImage::addkeyCommand(unsigned char key) {
++this->cmdpos;
drawChar((char) key, 78, this->cmdpos);
}
void ScreenImage::backspaceCommand() {
drawChar(' ', 78, this->cmdpos);
--this->cmdpos;
}
void ScreenImage::updateSlotName(const int slot, Card* card) {
int r(R_SLOT + slot);
int c(20);

View File

@ -36,11 +36,8 @@ private:
unsigned int* pixels;
int screen_pitch;
bool fullscreen;
bool hyper_a2_speed;
bool buffer;
bool fillLines;
AnalogTV::DisplayType display;
unsigned int cmdpos;
void createScreen();
std::vector<std::string> slotnames;
std::string cassInName;
@ -66,7 +63,6 @@ public:
void drawSlot(int slot, int r, int c);
void drawCassette();
void drawFnKeys();
void toggleHyperLabel();
void toggleKdbBufferLabel();
void cycleDisplayLabel();
void displayHz(int hz);
@ -76,11 +72,6 @@ public:
void updateSlotName(const int slot, Card* card);
void removeCard(const int slot, Card* card /* empty */);
void enterCommandMode();
void exitCommandMode();
void addkeyCommand(unsigned char key);
void backspaceCommand();
void setDiskFile(int slot, int drive, const std::filesystem::path& filename);
void setAnnunciator(int ann, bool on);