25#include <imgui_stdlib.h>
32using namespace std::literals;
38 for (
const auto& note : notes) {
39 buf.appendf(
"note.show=%d\n", note.show);
53 }
else if (name.starts_with(
"note.")) {
54 if (name.ends_with(
".show")) {
55 auto& note = notes.emplace_back();
57 }
else if (name.ends_with(
".text") && !notes.empty()) {
63static const std::vector<std::string>& getAllToyScripts(
ImGuiManager& manager)
65 static float refresh = FLT_MAX;
66 static std::vector<std::string> result;
71 if (
auto commands = manager.
execute(
TclObject(
"openmsx::all_command_names"))) {
73 for (
const auto& cmd : *commands) {
74 if (cmd.starts_with(
"toggle_")) {
75 result.emplace_back(cmd.view());
81 refresh += ImGui::GetIO().DeltaTime;
90 ImGui::MenuItem(
"Show virtual keyboard",
nullptr, &
manager.
keyboard->show);
92 ImGui::MenuItem(
"Show console", consoleShortCut.c_str(), &
manager.
console->show);
93 ImGui::MenuItem(
"Show message log ...",
nullptr, &
manager.
messages->logWindow.open);
96 std::string_view copyCommand =
"copy_screen_to_clipboard";
98 if (ImGui::MenuItem(
"Copy screen text to clipboard", copyShortCut.c_str(),
nullptr, motherBoard !=
nullptr)) {
101 std::string_view pasteCommand =
"type_clipboard";
103 if (ImGui::MenuItem(
"Paste clipboard into MSX", pasteShortCut.c_str(),
nullptr, motherBoard !=
nullptr)) {
106 if (ImGui::MenuItem(
"Simple notes widget ...")) {
113 auto& note = notes.emplace_back();
117 simpleToolTip(
"Typical use: dock into a larger layout to add free text.");
121 ImGui::MenuItem(
"Screenshot ...",
nullptr, &showScreenshot);
122 ImGui::MenuItem(
"Audio/Video ...",
nullptr, &showRecord);
129 ImGui::MenuItem(
"Trainer Selector ...",
nullptr, &
manager.
trainer->show);
138 const auto& toys = getAllToyScripts(
manager);
139 for (
const auto& toy : toys) {
140 std::string displayText = toy.substr(7);
142 if (ImGui::MenuItem(displayText.c_str())) {
156 if (showScreenshot) paintScreenshot();
157 if (showRecord) paintRecord();
160 const auto popupTitle =
"Confirm##Tools";
161 if (openConfirmPopup) {
162 openConfirmPopup =
false;
163 ImGui::OpenPopup(popupTitle);
165 im::PopupModal(popupTitle,
nullptr, ImGuiWindowFlags_AlwaysAutoResize, [&]{
169 if (ImGui::Button(
"Ok")) {
174 close |= ImGui::Button(
"Cancel");
176 ImGui::CloseCurrentPopup();
182static std::string_view stem(std::string_view fullName)
187bool ImGuiTools::screenshotNameExists()
const
194void ImGuiTools::generateScreenshotName()
197 screenshotName = result->getString();
199 if (screenshotName.empty()) {
200 screenshotName =
"openmsx";
202 if (screenshotNameExists()) {
203 nextScreenshotName();
207void ImGuiTools::nextScreenshotName()
209 std::string_view prefix = screenshotName;
211 if (prefix.size() > 4) {
212 auto counter = prefix.substr(prefix.size() - 4);
213 if (
ranges::all_of(counter, [](
char c) {
return (
'0' <= c) && (c <=
'9'); })) {
214 prefix.remove_suffix(4);
215 if (prefix.ends_with(
' ') || prefix.ends_with(
'_')) {
216 prefix.remove_suffix(1);
224void ImGuiTools::paintScreenshot()
226 ImGui::SetNextWindowSize(
gl::vec2{24, 17} * ImGui::GetFontSize(), ImGuiCond_FirstUseEver);
227 im::Window(
"Capture screenshot", &showScreenshot, [&]{
228 if (ImGui::IsWindowAppearing()) {
230 generateScreenshotName();
232 im::TreeNode(
"Settings", ImGuiTreeNodeFlags_DefaultOpen, [&]{
233 ImGui::RadioButton(
"Rendered image", &screenshotType,
static_cast<int>(SsType::RENDERED));
234 HelpMarker(
"Include all rendering effect like scale-algorithm, horizontal-stretch, color effects, ...");
236 ImGui::Checkbox(
"With OSD elements", &screenshotWithOsd);
237 HelpMarker(
"Include non-MSX elements, e.g. the GUI");
239 ImGui::RadioButton(
"Raw MSX image", &screenshotType,
static_cast<int>(SsType::MSX));
240 HelpMarker(
"The raw unscaled MSX image, without any rendering effects");
242 ImGui::RadioButton(
"320 x 240", &screenshotSize,
static_cast<int>(SsSize::S_320));
243 ImGui::RadioButton(
"640 x 480", &screenshotSize,
static_cast<int>(SsSize::S_640));
245 ImGui::Checkbox(
"Hide sprites", &screenshotHideSprites);
246 HelpMarker(
"Note: screen must be re-rendered for this, "
247 "so emulation must be (briefly) unpaused before the screenshot can be taken");
251 ImGui::AlignTextToFramePadding();
254 const auto& style = ImGui::GetStyle();
255 auto buttonWidth = style.ItemSpacing.x + 2.0f * style.FramePadding.x +
257 ImGui::SetNextItemWidth(-buttonWidth);
258 ImGui::InputText(
"##name", &screenshotName);
260 if (ImGui::Button(
"Create")) {
261 confirmCmd =
makeTclList(
"screenshot", screenshotName);
262 if (screenshotType ==
static_cast<int>(SsType::RENDERED)) {
263 if (screenshotWithOsd) {
268 if (screenshotSize ==
static_cast<int>(SsSize::S_640)) {
272 if (screenshotHideSprites) {
276 if (screenshotNameExists()) {
277 openConfirmPopup =
true;
278 confirmText =
strCat(
"Overwrite screenshot with name '", screenshotName,
"'?");
282 [&](
const TclObject&) { nextScreenshotName(); });
286 if (ImGui::Button(
"Open screenshots folder...")) {
293std::string ImGuiTools::getRecordFilename()
const
295 bool recordVideo = recordSource !=
static_cast<int>(Source::AUDIO);
299 recordName, directory,
"openmsx", extension);
302void ImGuiTools::paintRecord()
307 :
std::string(
"Capture Audio/Video");
310 im::TreeNode(
"Settings", ImGuiTreeNodeFlags_DefaultOpen, [&]{
313 ImGui::RadioButton(
"Audio", &recordSource,
static_cast<int>(Source::AUDIO));
314 ImGui::SameLine(0.0f, 30.0f);
315 ImGui::RadioButton(
"Video", &recordSource,
static_cast<int>(Source::VIDEO));
316 ImGui::SameLine(0.0f, 30.0f);
317 ImGui::RadioButton(
"Both", &recordSource,
static_cast<int>(Source::BOTH));
319 im::Disabled(recordSource ==
static_cast<int>(Source::VIDEO), [&]{
322 ImGui::RadioButton(
"Mono", &recordAudio,
static_cast<int>(Audio::MONO));
323 ImGui::SameLine(0.0f, 30.0f);
324 ImGui::RadioButton(
"Stereo", &recordAudio,
static_cast<int>(Audio::STEREO));
325 ImGui::SameLine(0.0f, 30.0f);
326 ImGui::RadioButton(
"Auto-detect", &recordAudio,
static_cast<int>(Audio::AUTO));
327 HelpMarker(
"At the start of the recording check if any stereo or "
328 "any off-center-balanced mono sound devices are present.");
331 im::Disabled(recordSource ==
static_cast<int>(Source::AUDIO), [&]{
334 ImGui::RadioButton(
"320 x 240", &recordVideoSize,
static_cast<int>(VideoSize::V_320));
335 ImGui::SameLine(0.0f, 30.0f);
336 ImGui::RadioButton(
"640 x 480", &recordVideoSize,
static_cast<int>(VideoSize::V_640));
337 ImGui::SameLine(0.0f, 30.0f);
338 ImGui::RadioButton(
"960 x 720", &recordVideoSize,
static_cast<int>(VideoSize::V_960));
343 ImGui::AlignTextToFramePadding();
346 const auto& style = ImGui::GetStyle();
347 auto buttonWidth = style.ItemSpacing.x + 2.0f * style.FramePadding.x +
349 ImGui::SetNextItemWidth(-buttonWidth);
350 ImGui::InputText(
"##name", &recordName);
352 if (!recording && ImGui::Button(
"Start")) {
354 if (!recordName.empty()) {
357 if (recordSource ==
static_cast<int>(Source::AUDIO)) {
359 }
else if (recordSource ==
static_cast<int>(Source::VIDEO)) {
362 if (recordSource !=
static_cast<int>(Source::VIDEO)) {
363 if (recordAudio ==
static_cast<int>(Audio::MONO)) {
365 }
else if (recordAudio ==
static_cast<int>(Audio::STEREO)) {
369 if (recordSource !=
static_cast<int>(Source::AUDIO)) {
370 if (recordVideoSize ==
static_cast<int>(VideoSize::V_640)) {
372 }
else if (recordVideoSize ==
static_cast<int>(VideoSize::V_960)) {
378 openConfirmPopup =
true;
379 confirmText =
strCat(
"Overwrite recording with name '", recordName,
"'?");
386 if (recording && ImGui::Button(
"Stop")) {
390 if (ImGui::Button(
"Open recordings folder...")) {
391 bool recordVideo = recordSource !=
static_cast<int>(Source::AUDIO);
398void ImGuiTools::paintNotes()
400 for (
auto [i, note] :
enumerate(notes)) {
401 if (!note.show)
continue;
404 ImGui::InputTextMultiline(
"##text", ¬e.text, {-FLT_MIN, -FLT_MIN});
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::unique_ptr< ImGuiWaveViewer > waveViewer
std::optional< TclObject > execute(TclObject command)
std::unique_ptr< ImGuiKeyboard > keyboard
std::unique_ptr< ImGuiConsole > console
std::unique_ptr< ImGuiMessages > messages
std::unique_ptr< ImGuiSCCViewer > sccViewer
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.
constexpr auto enumerate(Iterable &&iterable)
Heavily inspired by Nathan Reed's blog post: Python-Like enumerate() In C++17 http://reedbeta....
auto CalcTextSize(std::string_view str)
void TextUnformatted(const std::string &str)
bool stringToBool(string_view str)
std::string decode(std::string_view input)
std::string encode(std::string_view input)
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)
constexpr bool all_of(InputRange &&range, UnaryPredicate pred)
auto find(InputRange &&range, const T &value)
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)