1
0
mirror of https://github.com/TomHarte/CLK.git synced 2024-06-09 01:29:44 +00:00

Introduces Configurable::Device and implements it for the Electron.

Configurable::Device covers devices that have user-facing configuration options, listing them and accepting them.
This commit is contained in:
Thomas Harte 2017-11-17 23:02:00 -05:00
parent 532ea35ee9
commit de9db724a7
8 changed files with 145 additions and 9 deletions

View File

@ -0,0 +1,76 @@
//
// Configurable.h
// Clock Signal
//
// Created by Thomas Harte on 17/11/2017.
// Copyright © 2017 Thomas Harte. All rights reserved.
//
#ifndef Configurable_h
#define Configurable_h
#include <map>
#include <string>
#include <vector>
namespace Configurable {
/*!
The Option class hierarchy provides a way for components, machines, etc, to provide a named
list of typed options to which they can respond.
*/
struct Option {
std::string long_name;
std::string short_name;
virtual ~Option() {}
Option(const std::string &long_name, const std::string &short_name) : long_name(long_name), short_name(short_name) {}
};
struct BooleanOption: public Option {
BooleanOption(const std::string &long_name, const std::string &short_name) : Option(long_name, short_name) {}
};
struct ListOption: public Option {
std::vector<std::string> options;
ListOption(const std::string &long_name, const std::string &short_name, const std::vector<std::string> &options) : Option(long_name, short_name), options(options) {}
};
/*!
Selections are responses to Options.
*/
struct Selection {
virtual ~Selection() {}
};
struct BooleanSelection: public Selection {
bool value;
BooleanSelection(bool value) : value(value) {}
};
struct ListSelection: public Selection {
std::string value;
ListSelection(const std::string value) : value(value) {}
};
using SelectionSet = std::map<std::string, std::unique_ptr<Selection>>;
/*!
A Configuratble provides the options that it responds to and allows selections to be set.
*/
struct Device {
virtual std::vector<std::unique_ptr<Option>> get_options() = 0;
virtual void set_selections(const SelectionSet &selection_by_option) = 0;
virtual SelectionSet get_accurate_selections() = 0;
virtual SelectionSet get_user_friendly_selections() = 0;
};
template <typename T> T *selection(const Configurable::SelectionSet &selections_by_option, const std::string &name) {
auto selection = selections_by_option.find(name);
if(selection == selections_by_option.end()) return nullptr;
return dynamic_cast<T *>(selection->second.get());
}
}
#endif /* Configurable_h */

View File

@ -10,6 +10,9 @@
#define ConfigurationTarget_hpp
#include "../StaticAnalyser/StaticAnalyser.hpp"
#include "../Configurable/Configurable.hpp"
#include <string>
namespace ConfigurationTarget {

View File

@ -416,6 +416,35 @@ class ConcreteMachine:
return keyboard_mapper_;
}
std::vector<std::unique_ptr<Configurable::Option>> get_options() override {
std::vector<std::unique_ptr<Configurable::Option>> options;
options.emplace_back(new Configurable::BooleanOption("Load Tapes Quickly", "quickload"));
options.emplace_back(new Configurable::ListOption("Display", "display", {"composite", "rgb"}));
return options;
}
void set_selections(const Configurable::SelectionSet &selections_by_option) override {
auto quickload = Configurable::selection<Configurable::BooleanSelection>(selections_by_option, "quickload");
if(quickload) set_use_fast_tape_hack(quickload->value);
auto display = Configurable::selection<Configurable::ListSelection>(selections_by_option, "display");
if(display) get_crt()->set_output_device((display->value == "rgb") ? Outputs::CRT::OutputDevice::Monitor : Outputs::CRT::OutputDevice::Television);
}
Configurable::SelectionSet get_accurate_selections() override {
Configurable::SelectionSet selection_set;
selection_set["quickload"] = std::unique_ptr<Configurable::Selection>(new Configurable::BooleanSelection(false));
selection_set["display"] = std::unique_ptr<Configurable::Selection>(new Configurable::ListSelection("composite"));
return selection_set;
}
Configurable::SelectionSet get_user_friendly_selections() override {
Configurable::SelectionSet selection_set;
selection_set["quickload"] = std::unique_ptr<Configurable::Selection>(new Configurable::BooleanSelection(true));
selection_set["display"] = std::unique_ptr<Configurable::Selection>(new Configurable::ListSelection("rgb"));
return selection_set;
}
private:
inline void update_display() {
if(cycles_since_display_update_ > 0) {

View File

@ -9,6 +9,7 @@
#ifndef Electron_hpp
#define Electron_hpp
#include "../../Configurable/Configurable.hpp"
#include "../ConfigurationTarget.hpp"
#include "../CRTMachine.hpp"
#include "../KeyboardMachine.hpp"
@ -41,7 +42,8 @@ enum ROMSlot: uint8_t {
class Machine:
public CRTMachine::Machine,
public ConfigurationTarget::Machine,
public KeyboardMachine::Machine {
public KeyboardMachine::Machine,
public Configurable::Device {
public:
virtual ~Machine();

View File

@ -21,23 +21,30 @@ template<typename T> class TypedDynamicMachine: public ::Machine::DynamicMachine
public:
TypedDynamicMachine(T *machine) : machine_(machine) {}
ConfigurationTarget::Machine *configuration_target() {
return dynamic_cast<ConfigurationTarget::Machine *>(machine_.get());
ConfigurationTarget::Machine *configuration_target() override {
return get<ConfigurationTarget::Machine>();
}
CRTMachine::Machine *crt_machine() {
return dynamic_cast<CRTMachine::Machine *>(machine_.get());
CRTMachine::Machine *crt_machine() override {
return get<CRTMachine::Machine>();
}
JoystickMachine::Machine *joystick_machine() {
return dynamic_cast<JoystickMachine::Machine *>(machine_.get());
JoystickMachine::Machine *joystick_machine() override {
return get<JoystickMachine::Machine>();
}
KeyboardMachine::Machine *keyboard_machine() {
return dynamic_cast<KeyboardMachine::Machine *>(machine_.get());
KeyboardMachine::Machine *keyboard_machine() override {
return get<KeyboardMachine::Machine>();
}
Configurable::Device *configurable_device() override {
return get<Configurable::Device>();
}
private:
template <typename Class> Class *get() {
return dynamic_cast<Class *>(machine_.get());
}
std::unique_ptr<T> machine_;
};

View File

@ -11,6 +11,7 @@
#include "../../StaticAnalyser/StaticAnalyser.hpp"
#include "../../Configurable/Configurable.hpp"
#include "../ConfigurationTarget.hpp"
#include "../CRTMachine.hpp"
#include "../JoystickMachine.hpp"
@ -29,6 +30,7 @@ struct DynamicMachine {
virtual CRTMachine::Machine *crt_machine() = 0;
virtual JoystickMachine::Machine *joystick_machine() = 0;
virtual KeyboardMachine::Machine *keyboard_machine() = 0;
virtual Configurable::Device *configurable_device() = 0;
};
/*!

View File

@ -680,6 +680,7 @@
4B30512C1D989E2200B4FED8 /* Drive.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = Drive.hpp; sourceTree = "<group>"; };
4B30512E1D98ACC600B4FED8 /* Plus3.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = Plus3.cpp; path = Electron/Plus3.cpp; sourceTree = "<group>"; };
4B30512F1D98ACC600B4FED8 /* Plus3.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; name = Plus3.hpp; path = Electron/Plus3.hpp; sourceTree = "<group>"; };
4B31B88F1FBFBCD800C140D5 /* Configurable.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = Configurable.hpp; sourceTree = "<group>"; };
4B322DF31F5A26BF004EB04C /* 6502Implementation.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = 6502Implementation.hpp; sourceTree = "<group>"; };
4B322DF41F5A2714004EB04C /* 6502Storage.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = 6502Storage.hpp; sourceTree = "<group>"; };
4B322DFD1F5A2981004EB04C /* Z80AllRAM.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = Z80AllRAM.cpp; sourceTree = "<group>"; };
@ -1509,6 +1510,15 @@
name = Electron;
sourceTree = "<group>";
};
4B31B88E1FBFBCD800C140D5 /* Configurable */ = {
isa = PBXGroup;
children = (
4B31B88F1FBFBCD800C140D5 /* Configurable.hpp */,
);
name = Configurable;
path = ../../Configurable;
sourceTree = "<group>";
};
4B322DFC1F5A2981004EB04C /* AllRAM */ = {
isa = PBXGroup;
children = (
@ -2259,6 +2269,7 @@
4BF660691F281573002CB053 /* ClockReceiver */,
4BC9DF4A1D04691600F44158 /* Components */,
4B3940E81DA83C8700427841 /* Concurrency */,
4B31B88E1FBFBCD800C140D5 /* Configurable */,
4B055A761FAE78210060FFFF /* Frameworks */,
4B86E2581F8C628F006FAA45 /* Inputs */,
4BB73EDC1B587CA500552FC2 /* Machines */,

View File

@ -252,6 +252,12 @@ int main(int argc, char *argv[]) {
SDL_GetWindowSize(window, &window_width, &window_height);
std::cout << "Window size is " << window_width << ", " << window_height << std::endl;
// Establish user-friendly options by default.
Configurable::Device *configurable_device = machine->configurable_device();
if(configurable_device) {
configurable_device->set_selections(configurable_device->get_user_friendly_selections());
}
// Run the main event loop until the OS tells us to quit.
bool should_quit = false;
while(!should_quit) {