OXYGENHUB
◆ main openmsx / src / settings / VideoSourceSetting.cc
4.0 KiB · C++ · last changed chore(): initial commit 1 month ago source blame history raw
1
#include "VideoSourceSetting.hh"
2
3
#include "CommandException.hh"
4
#include "Completer.hh"
5
6
#include "StringOp.hh"
7
#include "stl.hh"
8
9
#include <algorithm>
10
11
namespace openmsx {
12
13
VideoSourceSetting::VideoSourceSetting(CommandController& commandController_)
14
	: Setting(commandController_, "videosource",
15
	          "selects the video source to display on the screen",
16
	          TclObject("none"), Save::NO)
17
{
18
	sources = { {.name = "none", .id = 0} };
19
20
	setChecker([this](const TclObject& newValue) {
21
		checkSetValue(newValue.getString()); // may throw
22
	});
23
	init();
24
}
25
26
void VideoSourceSetting::checkSetValue(std::string_view newValue) const
27
{
28
	// Special case: in case there are no video sources registered (yet),
29
	// the only allowed value is "none". In case there is at least one
30
	// registered source, this special value "none" should be hidden.
31
	if (((newValue == "none") && (sources.size() >  1)) ||
32
	    ((newValue != "none") && !has(newValue))) {
33
		throw CommandException("video source not available");
34
	}
35
}
36
37
int VideoSourceSetting::getSource() noexcept
38
{
39
	// Always try to find a better value than "none".
40
	if (std::string_view str = getValue().getString();
41
	    str != "none") {
42
		// If current value is allowed, then keep it.
43
		if (int id = has(str)) {
44
			return id;
45
		}
46
	}
47
	// Search the best value from the current set of allowed values.
48
	int id = 0;
49
	if (!id) { id = has("Video9000"); } // in
50
	if (!id) { id = has("MSX");       } //  order
51
	if (!id) { id = has("GFX9000");   } //   of
52
	if (!id) { id = has("Laserdisc"); } //    preference
53
	if (!id) {
54
		// This handles the "none" case, but also stuff like
55
		// multiple V99x8/V9990 chips. Prefer the source with
56
		// highest id (=newest).
57
		id = max_value(sources, &Source::id);
58
	}
59
	setSource(id); // store new value
60
	return id;
61
}
62
63
void VideoSourceSetting::setSource(int id)
64
{
65
	auto it = find_unguarded(sources, id, &Source::id);
66
	setValue(TclObject(it->name));
67
}
68
69
std::string_view VideoSourceSetting::getTypeString() const
70
{
71
	return "enumeration";
72
}
73
74
std::vector<std::string_view> VideoSourceSetting::getPossibleValues() const
75
{
76
	std::vector<std::string_view> result;
77
	if (sources.size() == 1) {
78
		assert(sources.front().name == "none");
79
		result.emplace_back("none");
80
	} else {
81
		for (const auto& [name, val] : sources) {
82
			if (val != 0) {
83
				result.emplace_back(name);
84
			}
85
		}
86
	}
87
	return result;
88
}
89
90
void VideoSourceSetting::additionalInfo(TclObject& result) const
91
{
92
	TclObject valueList;
93
	valueList.addListElements(getPossibleValues());
94
	result.addListElement(valueList);
95
}
96
97
void VideoSourceSetting::tabCompletion(std::vector<std::string>& tokens) const
98
{
99
	Completer::completeString(tokens, getPossibleValues(),
100
	                          false); // case insensitive
101
}
102
103
int VideoSourceSetting::registerVideoSource(const std::string& source)
104
{
105
	static int counter = 0; // id's are globally unique
106
107
	assert(!has(source));
108
	sources.emplace_back(source, ++counter);
109
110
	// First announce extended set of allowed values before announcing a
111
	// (possibly) different value.
112
	notifyPropertyChange();
113
	setSource(getSource()); // via source to (possibly) adjust value
114
115
	return counter;
116
}
117
118
void VideoSourceSetting::unregisterVideoSource(int source)
119
{
120
	move_pop_back(sources, rfind_unguarded(sources, source, &Source::id));
121
122
	// First notify the (possibly) changed value before announcing the
123
	// shrunken set of values.
124
	setSource(getSource()); // via source to (possibly) adjust value
125
	notifyPropertyChange();
126
}
127
128
bool VideoSourceSetting::has(int val) const
129
{
130
	return contains(sources, val, &Source::id);
131
}
132
133
int VideoSourceSetting::has(std::string_view val) const
134
{
135
	auto it = std::ranges::find_if(sources, [&](auto& p) {
136
		StringOp::casecmp cmp;
137
		return cmp(p.name, val);
138
	});
139
	return (it != end(sources)) ? it->id : 0;
140
}
141
142
143
VideoSourceActivator::VideoSourceActivator(
144
	VideoSourceSetting& setting_, const std::string& name)
145
	: setting(setting_)
146
	, id(setting.registerVideoSource(name))
147
{
148
}
149
150
VideoSourceActivator::~VideoSourceActivator()
151
{
152
	setting.unregisterVideoSource(id);
153
}
154
155
} // namespace openmsx