21#include <imgui_stdlib.h>
28using namespace std::literals;
40static const std::vector<std::string>& getAllToyScripts(
ImGuiManager& manager)
42 static float refresh = FLT_MAX;
43 static std::vector<std::string> result;
48 if (
auto commands = manager.
execute(
TclObject(
"openmsx::all_command_names"))) {
50 for (
const auto& cmd : *commands) {
51 if (cmd.starts_with(
"toggle_")) {
52 result.emplace_back(cmd.view());
58 refresh += ImGui::GetIO().DeltaTime;
67 ImGui::MenuItem(
"Show virtual keyboard",
nullptr, &
manager.
keyboard->show);
69 ImGui::MenuItem(
"Show console", consoleShortCut.c_str(), &
manager.
console->show);
70 ImGui::MenuItem(
"Show message log ...",
nullptr, &
manager.
messages->logWindow.open);
72 std::string_view copyCommand =
"copy_screen_to_clipboard";
74 if (ImGui::MenuItem(
"Copy screen text to clipboard", copyShortCut.c_str(),
nullptr, motherBoard !=
nullptr)) {
77 std::string_view pasteCommand =
"type_clipboard";
79 if (ImGui::MenuItem(
"Paste clipboard into MSX", pasteShortCut.c_str(),
nullptr, motherBoard !=
nullptr)) {
84 ImGui::MenuItem(
"Screenshot ...",
nullptr, &showScreenshot);
85 ImGui::MenuItem(
"Audio/Video ...",
nullptr, &showRecord);
90 ImGui::MenuItem(
"Trainer Selector ...",
nullptr, &
manager.
trainer->show);
95 const auto& toys = getAllToyScripts(
manager);
96 for (
const auto& toy : toys) {
97 std::string displayText = toy.substr(7);
99 if (ImGui::MenuItem(displayText.c_str())) {
113 if (showScreenshot) paintScreenshot();
114 if (showRecord) paintRecord();
116 const auto popupTitle =
"Confirm##Tools";
117 if (openConfirmPopup) {
118 openConfirmPopup =
false;
119 ImGui::OpenPopup(popupTitle);
121 im::PopupModal(popupTitle,
nullptr, ImGuiWindowFlags_AlwaysAutoResize, [&]{
125 if (ImGui::Button(
"Ok")) {
130 close |= ImGui::Button(
"Cancel");
132 ImGui::CloseCurrentPopup();
138static std::string_view stem(std::string_view fullName)
143bool ImGuiTools::screenshotNameExists()
const
150void ImGuiTools::generateScreenshotName()
153 screenshotName = result->getString();
155 if (screenshotName.empty()) {
156 screenshotName =
"openmsx";
158 if (screenshotNameExists()) {
159 nextScreenshotName();
163void ImGuiTools::nextScreenshotName()
165 std::string_view prefix = screenshotName;
167 if (prefix.size() > 4) {
168 auto counter = prefix.substr(prefix.size() - 4);
169 if (
ranges::all_of(counter, [](
char c) {
return (
'0' <= c) && (c <=
'9'); })) {
170 prefix.remove_suffix(4);
171 if (prefix.ends_with(
' ') || prefix.ends_with(
'_')) {
172 prefix.remove_suffix(1);
180void ImGuiTools::paintScreenshot()
182 ImGui::SetNextWindowSize(
gl::vec2{24, 17} * ImGui::GetFontSize(), ImGuiCond_FirstUseEver);
183 im::Window(
"Capture screenshot", &showScreenshot, [&]{
184 if (ImGui::IsWindowAppearing()) {
186 generateScreenshotName();
188 im::TreeNode(
"Settings", ImGuiTreeNodeFlags_DefaultOpen, [&]{
189 ImGui::RadioButton(
"Rendered image", &screenshotType,
static_cast<int>(SsType::RENDERED));
190 HelpMarker(
"Include all rendering effect like scale-algorithm, horizontal-stretch, color effects, ...");
192 ImGui::Checkbox(
"With OSD elements", &screenshotWithOsd);
193 HelpMarker(
"Include non-MSX elements, e.g. the GUI");
195 ImGui::RadioButton(
"Raw MSX image", &screenshotType,
static_cast<int>(SsType::MSX));
196 HelpMarker(
"The raw unscaled MSX image, without any rendering effects");
198 ImGui::RadioButton(
"320 x 240", &screenshotSize,
static_cast<int>(SsSize::S_320));
199 ImGui::RadioButton(
"640 x 480", &screenshotSize,
static_cast<int>(SsSize::S_640));
201 ImGui::Checkbox(
"Hide sprites", &screenshotHideSprites);
202 HelpMarker(
"Note: screen must be re-rendered for this, "
203 "so emulation must be (briefly) unpaused before the screenshot can be taken");
207 ImGui::AlignTextToFramePadding();
210 const auto& style = ImGui::GetStyle();
211 auto buttonWidth = style.ItemSpacing.x + 2.0f * style.FramePadding.x +
213 ImGui::SetNextItemWidth(-buttonWidth);
214 ImGui::InputText(
"##name", &screenshotName);
216 if (ImGui::Button(
"Create")) {
217 confirmCmd =
makeTclList(
"screenshot", screenshotName);
218 if (screenshotType ==
static_cast<int>(SsType::RENDERED)) {
219 if (screenshotWithOsd) {
224 if (screenshotSize ==
static_cast<int>(SsSize::S_640)) {
228 if (screenshotHideSprites) {
232 if (screenshotNameExists()) {
233 openConfirmPopup =
true;
234 confirmText =
strCat(
"Overwrite screenshot with name '", screenshotName,
"'?");
238 [&](
const TclObject&) { nextScreenshotName(); });
242 if (ImGui::Button(
"Open screenshots folder...")) {
249std::string ImGuiTools::getRecordFilename()
const
251 bool recordVideo = recordSource !=
static_cast<int>(Source::AUDIO);
255 recordName, directory,
"openmsx", extension);
258void ImGuiTools::paintRecord()
263 :
std::string(
"Capture Audio/Video");
266 im::TreeNode(
"Settings", ImGuiTreeNodeFlags_DefaultOpen, [&]{
269 ImGui::RadioButton(
"Audio", &recordSource,
static_cast<int>(Source::AUDIO));
270 ImGui::SameLine(0.0f, 30.0f);
271 ImGui::RadioButton(
"Video", &recordSource,
static_cast<int>(Source::VIDEO));
272 ImGui::SameLine(0.0f, 30.0f);
273 ImGui::RadioButton(
"Both", &recordSource,
static_cast<int>(Source::BOTH));
275 im::Disabled(recordSource ==
static_cast<int>(Source::VIDEO), [&]{
278 ImGui::RadioButton(
"Mono", &recordAudio,
static_cast<int>(Audio::MONO));
279 ImGui::SameLine(0.0f, 30.0f);
280 ImGui::RadioButton(
"Stereo", &recordAudio,
static_cast<int>(Audio::STEREO));
281 ImGui::SameLine(0.0f, 30.0f);
282 ImGui::RadioButton(
"Auto-detect", &recordAudio,
static_cast<int>(Audio::AUTO));
283 HelpMarker(
"At the start of the recording check if any stereo or "
284 "any off-center-balanced mono sound devices are present.");
287 im::Disabled(recordSource ==
static_cast<int>(Source::AUDIO), [&]{
290 ImGui::RadioButton(
"320 x 240", &recordVideoSize,
static_cast<int>(VideoSize::V_320));
291 ImGui::SameLine(0.0f, 30.0f);
292 ImGui::RadioButton(
"640 x 480", &recordVideoSize,
static_cast<int>(VideoSize::V_640));
293 ImGui::SameLine(0.0f, 30.0f);
294 ImGui::RadioButton(
"960 x 720", &recordVideoSize,
static_cast<int>(VideoSize::V_960));
299 ImGui::AlignTextToFramePadding();
302 const auto& style = ImGui::GetStyle();
303 auto buttonWidth = style.ItemSpacing.x + 2.0f * style.FramePadding.x +
305 ImGui::SetNextItemWidth(-buttonWidth);
306 ImGui::InputText(
"##name", &recordName);
308 if (!recording && ImGui::Button(
"Start")) {
310 if (!recordName.empty()) {
313 if (recordSource ==
static_cast<int>(Source::AUDIO)) {
315 }
else if (recordSource ==
static_cast<int>(Source::VIDEO)) {
318 if (recordSource !=
static_cast<int>(Source::VIDEO)) {
319 if (recordAudio ==
static_cast<int>(Audio::MONO)) {
321 }
else if (recordAudio ==
static_cast<int>(Audio::STEREO)) {
325 if (recordSource !=
static_cast<int>(Source::AUDIO)) {
326 if (recordVideoSize ==
static_cast<int>(VideoSize::V_640)) {
328 }
else if (recordVideoSize ==
static_cast<int>(VideoSize::V_960)) {
334 openConfirmPopup =
true;
335 confirmText =
strCat(
"Overwrite recording with name '", recordName,
"'?");
342 if (recording && ImGui::Button(
"Stop")) {
346 if (ImGui::Button(
"Open recordings folder...")) {
347 bool recordVideo = recordSource !=
static_cast<int>(Source::AUDIO);
static constexpr std::string_view AUDIO_DIR
static constexpr std::string_view VIDEO_DIR
static constexpr std::string_view AUDIO_EXTENSION
static constexpr std::string_view VIDEO_EXTENSION
static constexpr std::string_view SCREENSHOT_EXTENSION
static constexpr std::string_view SCREENSHOT_DIR
std::unique_ptr< ImGuiCheatFinder > cheatFinder
std::unique_ptr< ImGuiTrainer > trainer
std::unique_ptr< ImGuiDiskManipulator > diskManipulator
std::optional< TclObject > execute(TclObject command)
std::unique_ptr< ImGuiKeyboard > keyboard
std::unique_ptr< ImGuiConsole > console
std::unique_ptr< ImGuiMessages > messages
void executeDelayed(std::function< void()> action)
AviRecorder & getRecorder() const
void addListElement(const T &t)
Like std::string_view, but with the extra guarantee that it refers to a zero-terminated string.
auto CalcTextSize(std::string_view str)
void TextUnformatted(const std::string &str)
void DisabledIndent(bool b, std::invocable<> auto next)
void Window(const char *name, bool *p_open, ImGuiWindowFlags flags, std::invocable<> auto next)
bool TreeNode(const char *label, ImGuiTreeNodeFlags flags, std::invocable<> auto next)
void PopupModal(const char *name, bool *p_open, ImGuiWindowFlags flags, std::invocable<> auto next)
bool Menu(const char *label, bool enabled, std::invocable<> auto next)
void Disabled(bool b, std::invocable<> auto next)
string parseCommandFileArgument(string_view argument, string_view directory, string_view prefix, string_view extension)
Helper function for parsing filename arguments in Tcl commands.
bool exists(zstring_view filename)
Does this file (directory) exists?
string getNextNumberedFileName(string_view directory, string_view prefix, string_view extension, bool addSeparator)
Gets the next numbered file name with the specified prefix in the specified directory,...
const string & getUserOpenMSXDir()
Get the openMSX dir in the user's home directory.
string_view stripExtension(string_view path)
Returns the path without extension.
string_view getFilename(string_view path)
Returns the file portion of a path name.
This file implemented 3 utility functions:
bool loadOnePersistent(std::string_view name, zstring_view value, C &c, const std::tuple< Elements... > &tup)
void simpleToolTip(std::string_view desc)
void savePersistent(ImGuiTextBuffer &buf, C &c, const std::tuple< Elements... > &tup)
std::string getShortCutForCommand(const HotKey &hotkey, std::string_view command)
void HelpMarker(std::string_view desc)
TclObject makeTclList(Args &&... args)
bool all_of(InputRange &&range, UnaryPredicate pred)
constexpr void replace(ForwardRange &&range, const T &old_value, const T &new_value)
constexpr void sort(RandomAccessRange &&range)
size_t size(std::string_view utf8)
TemporaryString tmpStrCat(Ts &&... ts)