20 , osdCommand(commandController)
34 :
Command(commandController_,
"osd")
40 checkNumArgs(tokens, AtLeast{2},
"subcommand ?arg ...?");
41 executeSubCommand(tokens[1].getString(),
42 "create", [&]{
create(tokens, result); },
43 "destroy", [&]{ destroy(tokens, result); },
44 "info", [&]{ info(tokens, result); },
45 "exists", [&]{
exists(tokens, result); },
46 "configure", [&]{ configure(tokens, result); });
51 checkNumArgs(tokens, AtLeast{4}, Prefix{2},
"type name ?property value ...?");
52 std::string_view type = tokens[2].getString();
53 const auto& fullname = tokens[3];
54 auto fullnameStr = fullname.getString();
56 auto& gui =
OUTER(OSDGUI, osdCommand);
57 auto& top = gui.getTopWidget();
58 if (top.findByName(fullnameStr)) {
59 throw CommandException(
60 "There already exists a widget with this name: ",
65 auto* parent = childName.empty() ? &top : top.findByName(parentname);
67 throw CommandException(
68 "Parent widget doesn't exist yet:", parentname);
71 auto widget =
create(type, fullname);
72 auto* widget2 = widget.get();
73 configure(*widget, tokens.
subspan(4));
75 parent->addWidget(std::move(widget));
78 if (widget2->isVisible()) {
84 std::string_view type,
const TclObject& name)
const
86 auto& gui =
OUTER(OSDGUI, osdCommand);
87 if (type ==
"rectangle") {
88 return std::make_unique<OSDRectangle>(gui.display, name);
89 }
else if (type ==
"text") {
90 return std::make_unique<OSDText>(gui.display, name);
92 throw CommandException(
93 "Invalid widget type '", type,
"', expected "
94 "'rectangle' or 'text'.");
100 checkNumArgs(tokens, 3,
"name");
101 auto fullname = tokens[2].getString();
103 auto& gui =
OUTER(OSDGUI, osdCommand);
104 auto& top = gui.getTopWidget();
105 auto* widget = top.findByName(fullname);
112 auto* parent = widget->getParent();
114 throw CommandException(
"Can't destroy the top widget.");
117 if (widget->isVisible()) {
120 top.removeName(*widget);
121 parent->deleteWidget(*widget);
127 checkNumArgs(tokens, Between{2, 4}, Prefix{2},
"?name? ?property?");
128 auto& gui =
OUTER(OSDGUI, osdCommand);
129 switch (tokens.
size()) {
132 result.addListElements(gui.getTopWidget().getAllWidgetNames());
137 const auto& widget = getWidget(tokens[2].getString());
138 result.addListElements(widget.getProperties());
143 const auto& widget = getWidget(tokens[2].getString());
144 widget.getProperty(tokens[3].getString(), result);
152 checkNumArgs(tokens, 3,
"name");
153 auto& gui =
OUTER(OSDGUI, osdCommand);
154 auto* widget = gui.getTopWidget().findByName(tokens[2].getString());
155 result = widget !=
nullptr;
160 checkNumArgs(tokens, AtLeast{3},
"name ?property value ...?");
161 auto& widget = getWidget(tokens[2].getString());
162 configure(widget, tokens.
subspan(3));
163 if (widget.isVisible()) {
164 auto& gui =
OUTER(OSDGUI, osdCommand);
171 if (tokens.
size() & 1) {
173 throw CommandException(
174 "Missing value for '", tokens.
back().getString(),
"'.");
177 auto& interp = getInterpreter();
178 for (
size_t i = 0; i < tokens.
size(); i += 2) {
179 const auto& propName = tokens[i + 0].getString();
180 widget.setProperty(interp, propName, tokens[i + 1]);
186 if (tokens.
size() >= 2) {
187 if (tokens[1] ==
"create") {
189 "osd create <type> <widget-path> [<property-name> <property-value>]...\n"
191 "Creates a new OSD widget of given type. Path is a "
192 "hierarchical name for the widget (separated by '.'). "
193 "The parent widget for this new widget must already "
195 "Optionally you can set initial values for one or "
197 "This command returns the path of the newly created "
198 "widget. This is path is again needed to configure "
199 "or to remove the widget. It may be useful to assign "
200 "this path to a variable.";
201 }
else if (tokens[1] ==
"destroy") {
203 "osd destroy <widget-path>\n"
205 "Remove the specified OSD widget. Returns '1' on "
206 "success and '0' when widget couldn't be destroyed "
207 "because there was no widget with that name";
208 }
else if (tokens[1] ==
"info") {
210 "osd info [<widget-path> [<property-name>]]\n"
212 "Query various information about the OSD status. "
213 "You can call this command with 0, 1 or 2 arguments.\n"
214 "Without any arguments, this command returns a list "
215 "of all existing widget IDs.\n"
216 "When a path is given as argument, this command "
217 "returns a list of available properties for that widget.\n"
218 "When both path and property name arguments are "
219 "given, this command returns the current value of "
221 }
else if (tokens[1] ==
"exists") {
223 "osd exists <widget-path>\n"
225 "Test whether there exists a widget with given name. "
226 "This subcommand is meant to be used in scripts.";
227 }
else if (tokens[1] ==
"configure") {
229 "osd configure <widget-path> [<property-name> <property-value>]...\n"
231 "Modify one or more properties on the given widget.";
233 return "No such subcommand, see 'help osd'.";
237 "Low level OSD GUI commands\n"
238 " osd create <type> <widget-path> [<property-name> <property-value>]...\n"
239 " osd destroy <widget-path>\n"
240 " osd info [<widget-path> [<property-name>]]\n"
241 " osd exists <widget-path>\n"
242 " osd configure <widget-path> [<property-name> <property-value>]...\n"
243 "Use 'help osd <subcommand>' to see more info on a specific subcommand";
247 void OSDGUI::OSDCommand::tabCompletion(std::vector<std::string>& tokens)
const
249 using namespace std::literals;
250 auto& gui =
OUTER(OSDGUI, osdCommand);
251 if (tokens.size() == 2) {
252 static constexpr std::array cmds = {
253 "create"sv,
"destroy"sv,
"info"sv,
"exists"sv,
"configure"sv
255 completeString(tokens, cmds);
256 }
else if ((tokens.size() == 3) && (tokens[1] ==
"create")) {
257 static constexpr std::array types = {
"rectangle"sv,
"text"sv};
258 completeString(tokens, types);
259 }
else if ((tokens.size() == 3) ||
260 ((tokens.size() == 4) && (tokens[1] ==
"create"))) {
261 completeString(tokens, gui.getTopWidget().getAllWidgetNames());
264 auto properties = [&] {
265 if (tokens[1] ==
"create") {
266 auto widget =
create(tokens[2], TclObject());
267 return widget->getProperties();
268 }
else if (tokens[1] ==
one_of(
"configure",
"info")) {
269 const auto& widget = getWidget(tokens[2]);
270 return widget.getProperties();
275 completeString(tokens, properties);
276 }
catch (MSXException&) {
282 OSDWidget& OSDGUI::OSDCommand::getWidget(std::string_view name)
const
284 auto& gui =
OUTER(OSDGUI, osdCommand);
285 auto* widget = gui.getTopWidget().findByName(name);
287 throw CommandException(
"No widget with name ", name);
Represents the output window/screen of openMSX.
void repaintDelayed(uint64_t delta)
OSDGUI(CommandController &commandController, Display &display)
Display & getDisplay() const
constexpr subspan_return_t< Offset, Count > subspan() const
constexpr reference back() const
constexpr index_type size() const noexcept
std::pair< string_view, string_view > splitOnLast(string_view str, string_view chars)
bool exists(zstring_view filename)
Does this file (directory) exists?
std::unique_ptr< IDEDevice > create(const DeviceConfig &config)
This file implemented 3 utility functions:
#define OUTER(type, member)