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_")) {
76 if (cmd ==
"toggle_breaked")
continue;
77 result.emplace_back(cmd.view());
83 refresh += ImGui::GetIO().DeltaTime;
92 ImGui::MenuItem(
"Show virtual keyboard",
nullptr, &
manager.
keyboard->show);
94 ImGui::MenuItem(
"Show console", consoleShortCut.c_str(), &
manager.
console->show);
95 ImGui::MenuItem(
"Show message log ...",
nullptr, &
manager.
messages->logWindow.open);
98 std::string_view copyCommand =
"copy_screen_to_clipboard";
100 if (ImGui::MenuItem(
"Copy screen text to clipboard", copyShortCut.c_str(),
nullptr, motherBoard !=
nullptr)) {
103 std::string_view pasteCommand =
"type_clipboard";
105 if (ImGui::MenuItem(
"Paste clipboard into MSX", pasteShortCut.c_str(),
nullptr, motherBoard !=
nullptr)) {
108 if (ImGui::MenuItem(
"Simple notes widget ...")) {
115 auto& note = notes.emplace_back();
119 simpleToolTip(
"Typical use: dock into a larger layout to add free text.");
123 ImGui::MenuItem(
"Screenshot ...",
nullptr, &showScreenshot);
124 ImGui::MenuItem(
"Audio/Video ...",
nullptr, &showRecord);
131 ImGui::MenuItem(
"Trainer Selector ...",
nullptr, &
manager.
trainer->show);
140 const auto& toys = getAllToyScripts(
manager);
141 for (
const auto& toy : toys) {
142 std::string displayText = toy.substr(7);
144 if (ImGui::MenuItem(displayText.c_str())) {
158 if (showScreenshot) paintScreenshot();
159 if (showRecord) paintRecord();
162 const auto popupTitle =
"Confirm##Tools";
163 if (openConfirmPopup) {
164 openConfirmPopup =
false;
165 ImGui::OpenPopup(popupTitle);
167 im::PopupModal(popupTitle,
nullptr, ImGuiWindowFlags_AlwaysAutoResize, [&]{
171 if (ImGui::Button(
"Ok")) {
176 close |= ImGui::Button(
"Cancel");
178 ImGui::CloseCurrentPopup();
184static std::string_view stem(std::string_view fullName)
189bool ImGuiTools::screenshotNameExists()
const
196void ImGuiTools::generateScreenshotName()
199 screenshotName = result->getString();
201 if (screenshotName.empty()) {
202 screenshotName =
"openmsx";
204 if (screenshotNameExists()) {
205 nextScreenshotName();
209void ImGuiTools::nextScreenshotName()
211 std::string_view prefix = screenshotName;
213 if (prefix.size() > 4) {
214 auto counter = prefix.substr(prefix.size() - 4);
215 if (
ranges::all_of(counter, [](
char c) {
return (
'0' <= c) && (c <=
'9'); })) {
216 prefix.remove_suffix(4);
217 if (prefix.ends_with(
' ') || prefix.ends_with(
'_')) {
218 prefix.remove_suffix(1);
226void ImGuiTools::paintScreenshot()
228 ImGui::SetNextWindowSize(
gl::vec2{24, 17} * ImGui::GetFontSize(), ImGuiCond_FirstUseEver);
229 im::Window(
"Capture screenshot", &showScreenshot, [&]{
230 if (ImGui::IsWindowAppearing()) {
232 generateScreenshotName();
234 im::TreeNode(
"Settings", ImGuiTreeNodeFlags_DefaultOpen, [&]{
235 ImGui::RadioButton(
"Rendered image", &screenshotType,
static_cast<int>(SsType::RENDERED));
236 HelpMarker(
"Include all rendering effect like scale-algorithm, horizontal-stretch, color effects, ...");
238 ImGui::Checkbox(
"With OSD elements", &screenshotWithOsd);
239 HelpMarker(
"Include non-MSX elements, e.g. the GUI");
241 ImGui::RadioButton(
"Raw MSX image", &screenshotType,
static_cast<int>(SsType::MSX));
242 HelpMarker(
"The raw unscaled MSX image, without any rendering effects");
244 ImGui::RadioButton(
"320 x 240", &screenshotSize,
static_cast<int>(SsSize::S_320));
245 ImGui::RadioButton(
"640 x 480", &screenshotSize,
static_cast<int>(SsSize::S_640));
247 ImGui::Checkbox(
"Hide sprites", &screenshotHideSprites);
248 HelpMarker(
"Note: screen must be re-rendered for this, "
249 "so emulation must be (briefly) unpaused before the screenshot can be taken");
253 ImGui::AlignTextToFramePadding();
256 const auto& style = ImGui::GetStyle();
257 auto buttonWidth = style.ItemSpacing.x + 2.0f * style.FramePadding.x +
259 ImGui::SetNextItemWidth(-buttonWidth);
260 ImGui::InputText(
"##name", &screenshotName);
262 if (ImGui::Button(
"Create")) {
263 confirmCmd =
makeTclList(
"screenshot", screenshotName);
264 if (screenshotType ==
static_cast<int>(SsType::RENDERED)) {
265 if (screenshotWithOsd) {
270 if (screenshotSize ==
static_cast<int>(SsSize::S_640)) {
274 if (screenshotHideSprites) {
278 if (screenshotNameExists()) {
279 openConfirmPopup =
true;
280 confirmText =
strCat(
"Overwrite screenshot with name '", screenshotName,
"'?");
284 [&](
const TclObject&) { nextScreenshotName(); });
288 if (ImGui::Button(
"Open screenshots folder...")) {
295std::string ImGuiTools::getRecordFilename()
const
297 bool recordVideo = recordSource !=
static_cast<int>(Source::AUDIO);
301 recordName, directory,
"openmsx", extension);
304void ImGuiTools::paintRecord()
309 :
std::string(
"Capture Audio/Video");
312 im::TreeNode(
"Settings", ImGuiTreeNodeFlags_DefaultOpen, [&]{
315 ImGui::RadioButton(
"Audio", &recordSource,
static_cast<int>(Source::AUDIO));
316 ImGui::SameLine(0.0f, 30.0f);
317 ImGui::RadioButton(
"Video", &recordSource,
static_cast<int>(Source::VIDEO));
318 ImGui::SameLine(0.0f, 30.0f);
319 ImGui::RadioButton(
"Both", &recordSource,
static_cast<int>(Source::BOTH));
321 im::Disabled(recordSource ==
static_cast<int>(Source::VIDEO), [&]{
324 ImGui::RadioButton(
"Mono", &recordAudio,
static_cast<int>(Audio::MONO));
325 ImGui::SameLine(0.0f, 30.0f);
326 ImGui::RadioButton(
"Stereo", &recordAudio,
static_cast<int>(Audio::STEREO));
327 ImGui::SameLine(0.0f, 30.0f);
328 ImGui::RadioButton(
"Auto-detect", &recordAudio,
static_cast<int>(Audio::AUTO));
329 HelpMarker(
"At the start of the recording check if any stereo or "
330 "any off-center-balanced mono sound devices are present.");
333 im::Disabled(recordSource ==
static_cast<int>(Source::AUDIO), [&]{
336 ImGui::RadioButton(
"320 x 240", &recordVideoSize,
static_cast<int>(VideoSize::V_320));
337 ImGui::SameLine(0.0f, 30.0f);
338 ImGui::RadioButton(
"640 x 480", &recordVideoSize,
static_cast<int>(VideoSize::V_640));
339 ImGui::SameLine(0.0f, 30.0f);
340 ImGui::RadioButton(
"960 x 720", &recordVideoSize,
static_cast<int>(VideoSize::V_960));
345 ImGui::AlignTextToFramePadding();
348 const auto& style = ImGui::GetStyle();
349 auto buttonWidth = style.ItemSpacing.x + 2.0f * style.FramePadding.x +
351 ImGui::SetNextItemWidth(-buttonWidth);
352 ImGui::InputText(
"##name", &recordName);
354 if (!recording && ImGui::Button(
"Start")) {
356 if (!recordName.empty()) {
359 if (recordSource ==
static_cast<int>(Source::AUDIO)) {
361 }
else if (recordSource ==
static_cast<int>(Source::VIDEO)) {
364 if (recordSource !=
static_cast<int>(Source::VIDEO)) {
365 if (recordAudio ==
static_cast<int>(Audio::MONO)) {
367 }
else if (recordAudio ==
static_cast<int>(Audio::STEREO)) {
371 if (recordSource !=
static_cast<int>(Source::AUDIO)) {
372 if (recordVideoSize ==
static_cast<int>(VideoSize::V_640)) {
374 }
else if (recordVideoSize ==
static_cast<int>(VideoSize::V_960)) {
380 openConfirmPopup =
true;
381 confirmText =
strCat(
"Overwrite recording with name '", recordName,
"'?");
388 if (recording && ImGui::Button(
"Stop")) {
392 if (ImGui::Button(
"Open recordings folder...")) {
393 bool recordVideo = recordSource !=
static_cast<int>(Source::AUDIO);
400void ImGuiTools::paintNotes()
402 for (
auto [i, note_] :
enumerate(notes)) {
404 if (!note.show)
continue;
407 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)