mirror of
https://github.com/TomHarte/CLK.git
synced 2025-01-11 08:30:55 +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:
parent
532ea35ee9
commit
de9db724a7
76
Configurable/Configurable.hpp
Normal file
76
Configurable/Configurable.hpp
Normal 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 */
|
@ -10,6 +10,9 @@
|
||||
#define ConfigurationTarget_hpp
|
||||
|
||||
#include "../StaticAnalyser/StaticAnalyser.hpp"
|
||||
#include "../Configurable/Configurable.hpp"
|
||||
|
||||
#include <string>
|
||||
|
||||
namespace ConfigurationTarget {
|
||||
|
||||
|
@ -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) {
|
||||
|
@ -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();
|
||||
|
||||
|
@ -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_;
|
||||
};
|
||||
|
||||
|
@ -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;
|
||||
};
|
||||
|
||||
/*!
|
||||
|
@ -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 */,
|
||||
|
@ -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) {
|
||||
|
Loading…
x
Reference in New Issue
Block a user