24 , osdCommand(commandController)
38 :
Command(commandController_,
"osd")
42void OSDGUI::OSDCommand::execute(std::span<const TclObject> tokens, TclObject& result)
44 checkNumArgs(tokens, AtLeast{2},
"subcommand ?arg ...?");
45 executeSubCommand(tokens[1].getString(),
46 "create", [&]{
create(tokens, result); },
47 "destroy", [&]{ destroy(tokens, result); },
48 "info", [&]{ info(tokens, result); },
49 "exists", [&]{
exists(tokens, result); },
50 "configure", [&]{ configure(tokens, result); });
53void OSDGUI::OSDCommand::create(std::span<const TclObject> tokens, TclObject& result)
55 checkNumArgs(tokens, AtLeast{4}, Prefix{2},
"type name ?property value ...?");
56 std::string_view type = tokens[2].getString();
57 const auto& fullname = tokens[3];
58 auto fullnameStr = fullname.getString();
60 auto& gui =
OUTER(OSDGUI, osdCommand);
61 auto& top = gui.getTopWidget();
62 if (top.findByName(fullnameStr)) {
63 throw CommandException(
64 "There already exists a widget with this name: ",
69 auto* parent = childName.empty() ? &top : top.findByName(parentName);
71 throw CommandException(
72 "Parent widget doesn't exist yet:", parentName);
75 auto widget =
create(type, fullname);
76 const auto* widget2 = widget.get();
77 configure(*widget, tokens.subspan(4));
79 parent->addWidget(std::move(widget));
82 if (widget2->isVisible()) {
87std::unique_ptr<OSDWidget> OSDGUI::OSDCommand::create(
88 std::string_view type,
const TclObject& name)
const
90 auto& gui =
OUTER(OSDGUI, osdCommand);
91 if (type ==
"rectangle") {
92 return std::make_unique<OSDRectangle>(gui.display, name);
93 }
else if (type ==
"text") {
94 return std::make_unique<OSDText>(gui.display, name);
96 throw CommandException(
97 "Invalid widget type '", type,
"', expected "
98 "'rectangle' or 'text'.");
102void OSDGUI::OSDCommand::destroy(std::span<const TclObject> tokens, TclObject& result)
104 checkNumArgs(tokens, 3,
"name");
105 auto fullname = tokens[2].getString();
107 auto& gui =
OUTER(OSDGUI, osdCommand);
108 auto& top = gui.getTopWidget();
109 auto* widget = top.findByName(fullname);
116 auto* parent = widget->getParent();
118 throw CommandException(
"Can't destroy the top widget.");
121 if (widget->isVisible()) {
124 top.removeName(*widget);
125 parent->deleteWidget(*widget);
129void OSDGUI::OSDCommand::info(std::span<const TclObject> tokens, TclObject& result)
131 checkNumArgs(tokens, Between{2, 4}, Prefix{2},
"?name? ?property?");
132 auto& gui =
OUTER(OSDGUI, osdCommand);
133 switch (tokens.size()) {
136 result.addListElements(gui.getTopWidget().getAllWidgetNames());
141 const auto& widget = getWidget(tokens[2].getString());
142 result.addListElements(widget.getProperties());
147 const auto& widget = getWidget(tokens[2].getString());
148 widget.getProperty(tokens[3].getString(), result);
154void OSDGUI::OSDCommand::exists(std::span<const TclObject> tokens, TclObject& result)
156 checkNumArgs(tokens, 3,
"name");
157 auto& gui =
OUTER(OSDGUI, osdCommand);
158 const auto* widget = gui.getTopWidget().findByName(tokens[2].getString());
159 result = widget !=
nullptr;
162void OSDGUI::OSDCommand::configure(std::span<const TclObject> tokens, TclObject& )
164 checkNumArgs(tokens, AtLeast{3},
"name ?property value ...?");
165 auto& widget = getWidget(tokens[2].getString());
166 configure(widget, tokens.subspan(3));
167 if (widget.isVisible()) {
168 const auto& gui =
OUTER(OSDGUI, osdCommand);
173void OSDGUI::OSDCommand::configure(OSDWidget& widget, std::span<const TclObject> tokens)
const
175 if (tokens.size() & 1) {
177 throw CommandException(
178 "Missing value for '", tokens.back().getString(),
"'.");
181 auto& interp = getInterpreter();
182 for (
size_t i = 0; i < tokens.size(); i += 2) {
183 const auto& propName = tokens[i + 0].getString();
184 widget.setProperty(interp, propName, tokens[i + 1]);
188std::string OSDGUI::OSDCommand::help(std::span<const TclObject> tokens)
const
190 if (tokens.size() >= 2) {
191 if (tokens[1] ==
"create") {
193 "osd create <type> <widget-path> [<property-name> <property-value>]...\n"
195 "Creates a new OSD widget of given type. Path is a "
196 "hierarchical name for the widget (separated by '.'). "
197 "The parent widget for this new widget must already "
199 "Optionally you can set initial values for one or "
201 "This command returns the path of the newly created "
202 "widget. This is path is again needed to configure "
203 "or to remove the widget. It may be useful to assign "
204 "this path to a variable.";
205 }
else if (tokens[1] ==
"destroy") {
207 "osd destroy <widget-path>\n"
209 "Remove the specified OSD widget. Returns '1' on "
210 "success and '0' when widget couldn't be destroyed "
211 "because there was no widget with that name";
212 }
else if (tokens[1] ==
"info") {
214 "osd info [<widget-path> [<property-name>]]\n"
216 "Query various information about the OSD status. "
217 "You can call this command with 0, 1 or 2 arguments.\n"
218 "Without any arguments, this command returns a list "
219 "of all existing widget IDs.\n"
220 "When a path is given as argument, this command "
221 "returns a list of available properties for that widget.\n"
222 "When both path and property name arguments are "
223 "given, this command returns the current value of "
225 }
else if (tokens[1] ==
"exists") {
227 "osd exists <widget-path>\n"
229 "Test whether there exists a widget with given name. "
230 "This subcommand is meant to be used in scripts.";
231 }
else if (tokens[1] ==
"configure") {
233 "osd configure <widget-path> [<property-name> <property-value>]...\n"
235 "Modify one or more properties on the given widget.";
237 return "No such subcommand, see 'help osd'.";
241 "Low level OSD GUI commands\n"
242 " osd create <type> <widget-path> [<property-name> <property-value>]...\n"
243 " osd destroy <widget-path>\n"
244 " osd info [<widget-path> [<property-name>]]\n"
245 " osd exists <widget-path>\n"
246 " osd configure <widget-path> [<property-name> <property-value>]...\n"
247 "Use 'help osd <subcommand>' to see more info on a specific subcommand";
251void OSDGUI::OSDCommand::tabCompletion(std::vector<std::string>& tokens)
const
253 using namespace std::literals;
254 auto& gui =
OUTER(OSDGUI, osdCommand);
255 if (tokens.size() == 2) {
256 static constexpr std::array cmds = {
257 "create"sv,
"destroy"sv,
"info"sv,
"exists"sv,
"configure"sv
259 completeString(tokens, cmds);
260 }
else if ((tokens.size() == 3) && (tokens[1] ==
"create")) {
261 static constexpr std::array types = {
"rectangle"sv,
"text"sv};
262 completeString(tokens, types);
263 }
else if ((tokens.size() == 3) ||
264 ((tokens.size() == 4) && (tokens[1] ==
"create"))) {
265 completeString(tokens, gui.getTopWidget().getAllWidgetNames());
268 auto properties = [&] {
269 if (tokens[1] ==
"create") {
270 auto widget =
create(tokens[2], TclObject());
271 return widget->getProperties();
272 }
else if (tokens[1] ==
one_of(
"configure",
"info")) {
273 const auto& widget = getWidget(tokens[2]);
274 return widget.getProperties();
276 return std::span<const std::string_view>{};
279 completeString(tokens, properties);
280 }
catch (MSXException&) {
286OSDWidget& OSDGUI::OSDCommand::getWidget(std::string_view name)
const
288 auto& gui =
OUTER(OSDGUI, osdCommand);
289 auto* widget = gui.getTopWidget().findByName(name);
291 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)