21 , osdCommand(commandController)
35 :
Command(commandController_,
"osd")
39void OSDGUI::OSDCommand::execute(std::span<const TclObject> tokens, TclObject& result)
41 checkNumArgs(tokens, AtLeast{2},
"subcommand ?arg ...?");
42 executeSubCommand(tokens[1].getString(),
43 "create", [&]{
create(tokens, result); },
44 "destroy", [&]{ destroy(tokens, result); },
45 "info", [&]{ info(tokens, result); },
46 "exists", [&]{
exists(tokens, result); },
47 "configure", [&]{ configure(tokens, result); });
52 checkNumArgs(tokens, AtLeast{4}, Prefix{2},
"type name ?property value ...?");
53 std::string_view type = tokens[2].getString();
54 const auto& fullname = tokens[3];
55 auto fullnameStr = fullname.getString();
57 auto& gui =
OUTER(OSDGUI, osdCommand);
58 auto& top = gui.getTopWidget();
59 if (top.findByName(fullnameStr)) {
60 throw CommandException(
61 "There already exists a widget with this name: ",
66 auto* parent = childName.empty() ? &top : top.findByName(parentName);
68 throw CommandException(
69 "Parent widget doesn't exist yet:", parentName);
72 auto widget =
create(type, fullname);
73 auto* widget2 = widget.get();
74 configure(*widget, tokens.subspan(4));
76 parent->addWidget(std::move(widget));
79 if (widget2->isVisible()) {
85 std::string_view type,
const TclObject& name)
const
87 auto& gui =
OUTER(OSDGUI, osdCommand);
88 if (type ==
"rectangle") {
89 return std::make_unique<OSDRectangle>(gui.display, name);
90 }
else if (type ==
"text") {
91 return std::make_unique<OSDText>(gui.display, name);
93 throw CommandException(
94 "Invalid widget type '", type,
"', expected "
95 "'rectangle' or 'text'.");
99void OSDGUI::OSDCommand::destroy(std::span<const TclObject> tokens, TclObject& result)
101 checkNumArgs(tokens, 3,
"name");
102 auto fullname = tokens[2].getString();
104 auto& gui =
OUTER(OSDGUI, osdCommand);
105 auto& top = gui.getTopWidget();
106 auto* widget = top.findByName(fullname);
113 auto* parent = widget->getParent();
115 throw CommandException(
"Can't destroy the top widget.");
118 if (widget->isVisible()) {
121 top.removeName(*widget);
122 parent->deleteWidget(*widget);
126void OSDGUI::OSDCommand::info(std::span<const TclObject> tokens, TclObject& result)
128 checkNumArgs(tokens, Between{2, 4}, Prefix{2},
"?name? ?property?");
129 auto& gui =
OUTER(OSDGUI, osdCommand);
130 switch (tokens.size()) {
133 result.addListElements(gui.getTopWidget().getAllWidgetNames());
138 const auto& widget = getWidget(tokens[2].getString());
139 result.addListElements(widget.getProperties());
144 const auto& widget = getWidget(tokens[2].getString());
145 widget.getProperty(tokens[3].getString(), result);
153 checkNumArgs(tokens, 3,
"name");
154 auto& gui =
OUTER(OSDGUI, osdCommand);
155 auto* widget = gui.getTopWidget().findByName(tokens[2].getString());
156 result = widget !=
nullptr;
159void OSDGUI::OSDCommand::configure(std::span<const TclObject> tokens, TclObject& )
161 checkNumArgs(tokens, AtLeast{3},
"name ?property value ...?");
162 auto& widget = getWidget(tokens[2].getString());
163 configure(widget, tokens.subspan(3));
164 if (widget.isVisible()) {
165 auto& gui =
OUTER(OSDGUI, osdCommand);
170void OSDGUI::OSDCommand::configure(OSDWidget& widget, std::span<const TclObject> tokens)
172 if (tokens.size() & 1) {
174 throw CommandException(
175 "Missing value for '", tokens.back().getString(),
"'.");
178 auto& interp = getInterpreter();
179 for (
size_t i = 0; i < tokens.size(); i += 2) {
180 const auto& propName = tokens[i + 0].getString();
181 widget.setProperty(interp, propName, tokens[i + 1]);
185std::string OSDGUI::OSDCommand::help(std::span<const TclObject> tokens)
const
187 if (tokens.size() >= 2) {
188 if (tokens[1] ==
"create") {
190 "osd create <type> <widget-path> [<property-name> <property-value>]...\n"
192 "Creates a new OSD widget of given type. Path is a "
193 "hierarchical name for the widget (separated by '.'). "
194 "The parent widget for this new widget must already "
196 "Optionally you can set initial values for one or "
198 "This command returns the path of the newly created "
199 "widget. This is path is again needed to configure "
200 "or to remove the widget. It may be useful to assign "
201 "this path to a variable.";
202 }
else if (tokens[1] ==
"destroy") {
204 "osd destroy <widget-path>\n"
206 "Remove the specified OSD widget. Returns '1' on "
207 "success and '0' when widget couldn't be destroyed "
208 "because there was no widget with that name";
209 }
else if (tokens[1] ==
"info") {
211 "osd info [<widget-path> [<property-name>]]\n"
213 "Query various information about the OSD status. "
214 "You can call this command with 0, 1 or 2 arguments.\n"
215 "Without any arguments, this command returns a list "
216 "of all existing widget IDs.\n"
217 "When a path is given as argument, this command "
218 "returns a list of available properties for that widget.\n"
219 "When both path and property name arguments are "
220 "given, this command returns the current value of "
222 }
else if (tokens[1] ==
"exists") {
224 "osd exists <widget-path>\n"
226 "Test whether there exists a widget with given name. "
227 "This subcommand is meant to be used in scripts.";
228 }
else if (tokens[1] ==
"configure") {
230 "osd configure <widget-path> [<property-name> <property-value>]...\n"
232 "Modify one or more properties on the given widget.";
234 return "No such subcommand, see 'help osd'.";
238 "Low level OSD GUI commands\n"
239 " osd create <type> <widget-path> [<property-name> <property-value>]...\n"
240 " osd destroy <widget-path>\n"
241 " osd info [<widget-path> [<property-name>]]\n"
242 " osd exists <widget-path>\n"
243 " osd configure <widget-path> [<property-name> <property-value>]...\n"
244 "Use 'help osd <subcommand>' to see more info on a specific subcommand";
248void OSDGUI::OSDCommand::tabCompletion(std::vector<std::string>& tokens)
const
250 using namespace std::literals;
251 auto& gui =
OUTER(OSDGUI, osdCommand);
252 if (tokens.size() == 2) {
253 static constexpr std::array cmds = {
254 "create"sv,
"destroy"sv,
"info"sv,
"exists"sv,
"configure"sv
256 completeString(tokens, cmds);
257 }
else if ((tokens.size() == 3) && (tokens[1] ==
"create")) {
258 static constexpr std::array types = {
"rectangle"sv,
"text"sv};
259 completeString(tokens, types);
260 }
else if ((tokens.size() == 3) ||
261 ((tokens.size() == 4) && (tokens[1] ==
"create"))) {
262 completeString(tokens, gui.getTopWidget().getAllWidgetNames());
265 auto properties = [&] {
266 if (tokens[1] ==
"create") {
267 auto widget =
create(tokens[2], TclObject());
268 return widget->getProperties();
269 }
else if (tokens[1] ==
one_of(
"configure",
"info")) {
270 const auto& widget = getWidget(tokens[2]);
271 return widget.getProperties();
273 return std::span<const std::string_view>{};
276 completeString(tokens, properties);
277 }
catch (MSXException&) {
283OSDWidget& OSDGUI::OSDCommand::getWidget(std::string_view name)
const
285 auto& gui =
OUTER(OSDGUI, osdCommand);
286 auto* widget = gui.getTopWidget().findByName(name);
288 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
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)