diff options
| author | yum <yum.food.vr@gmail.com> | 2023-02-04 14:48:44 -0800 |
|---|---|---|
| committer | yum <yum.food.vr@gmail.com> | 2023-02-04 15:26:41 -0800 |
| commit | c3db83cdc93509fb242c9f5d62f2a2f3e21d376c (patch) | |
| tree | 0ad3ebba01dc95e41a41c623b14ba2d7c98954ef /GUI | |
| parent | 92fea304613bacfa014e1fbaf9fddb82e4f33d62 (diff) | |
GUI: Add debug panelv0.5.0
Add debug panel with options to show installed packages, clear the pip
cache, reset venv, and clear OSC configs.
* Refactor synchronous command execution + logging pattern inside
PythonWrapper
Diffstat (limited to 'GUI')
| -rw-r--r-- | GUI/GUI/GUI/Frame.cpp | 164 | ||||
| -rw-r--r-- | GUI/GUI/GUI/Frame.h | 7 | ||||
| -rw-r--r-- | GUI/GUI/GUI/PythonWrapper.cpp | 210 | ||||
| -rw-r--r-- | GUI/GUI/GUI/PythonWrapper.h | 3 |
4 files changed, 220 insertions, 164 deletions
diff --git a/GUI/GUI/GUI/Frame.cpp b/GUI/GUI/GUI/Frame.cpp index e0663c5..75d9e82 100644 --- a/GUI/GUI/GUI/Frame.cpp +++ b/GUI/GUI/GUI/Frame.cpp @@ -16,6 +16,7 @@ namespace { ID_NAVBAR,
ID_NAVBAR_BUTTON_TRANSCRIBE,
ID_NAVBAR_BUTTON_UNITY,
+ ID_NAVBAR_BUTTON_DEBUG,
ID_PY_PANEL,
ID_PY_CONFIG_PANEL,
ID_PY_APP_CONFIG_PANEL_PAIRS,
@@ -57,6 +58,13 @@ namespace { ID_UNITY_BYTES_PER_CHAR,
ID_UNITY_ROWS,
ID_UNITY_COLS,
+ ID_DEBUG_PANEL,
+ ID_DEBUG_OUT,
+ ID_DEBUG_CONFIG_PANEL,
+ ID_DEBUG_BUTTON_CLEAR_PIP,
+ ID_DEBUG_BUTTON_LIST_PIP,
+ ID_DEBUG_BUTTON_RESET_VENV,
+ ID_DEBUG_BUTTON_CLEAR_OSC,
};
const wxString kMicChoices[] = {
@@ -278,12 +286,14 @@ Frame::Frame() {
auto* navbar_button_transcribe = new wxButton(navbar, ID_NAVBAR_BUTTON_TRANSCRIBE, "Transcription");
auto* navbar_button_unity = new wxButton(navbar, ID_NAVBAR_BUTTON_UNITY, "Unity");
+ auto* navbar_button_debug = new wxButton(navbar, ID_NAVBAR_BUTTON_DEBUG, "Debug");
auto* sizer = new wxBoxSizer(wxVERTICAL);
navbar->SetSizer(sizer);
sizer->Add(navbar_button_transcribe, /*proportion=*/0, /*flags=*/wxEXPAND);
sizer->Add(navbar_button_unity, /*proportion=*/0, /*flags=*/wxEXPAND);
+ sizer->Add(navbar_button_debug, /*proportion=*/0, /*flags=*/wxEXPAND);
}
auto* transcribe_panel = new wxPanel(main_panel, ID_PY_PANEL);
@@ -706,22 +716,93 @@ Frame::Frame() }
unity_panel_->Hide();
+ auto* debug_panel = new wxPanel(main_panel, ID_DEBUG_PANEL);
+ debug_panel_ = debug_panel;
+ {
+ const auto debug_out_sz = wxSize(/*x_px=*/480, /*y_px=*/160);
+ auto* debug_out = new wxTextCtrl(debug_panel, ID_DEBUG_OUT,
+ wxEmptyString,
+ wxDefaultPosition,
+ debug_out_sz, wxTE_MULTILINE | wxTE_READONLY);
+ debug_out->SetMinSize(debug_out_sz);
+ debug_out_ = debug_out;
+
+ auto* debug_config_panel = new wxPanel(debug_panel, ID_DEBUG_CONFIG_PANEL);
+ {
+ auto* debug_button_list_pip = new wxButton(debug_config_panel, ID_DEBUG_BUTTON_LIST_PIP, "List pip packages");
+ debug_button_list_pip->SetToolTip(
+ "List the packages (and versions) installed in the "
+ "virtual environment by pip. Also list the contents "
+ "of the pip cache.");
+ debug_button_list_pip->SetWindowStyleFlag(wxBU_EXACTFIT);
+
+ auto* debug_button_clear_pip = new wxButton(debug_config_panel, ID_DEBUG_BUTTON_CLEAR_PIP, "Clear pip cache");
+ // The real explanation: we install a special version of torch
+ // using --extra-index-url, and I'm like 99% sure that pip
+ // doesn't correctly detect that we want this version instead
+ // of the normal version.
+ debug_button_clear_pip->SetToolTip(
+ "TaSTT uses a piece of software called pip to install "
+ "Python dependencies. To enable reusing packages across "
+ "different Python projects, pip installs packages in a "
+ "system-wide cache. Sometimes the contents of this cache "
+ "can get stale (it's complicated) and clearing the cache "
+ "can fix issues.");
+ debug_button_clear_pip->SetWindowStyleFlag(wxBU_EXACTFIT);
+
+ auto* debug_button_reset_venv = new wxButton(debug_config_panel, ID_DEBUG_BUTTON_RESET_VENV, "Reset python virtual environment");
+ debug_button_reset_venv->SetToolTip(
+ "Uninstall all Python packages installed into the virtual "
+ "environment. Do this after clearing pip!");
+ debug_button_reset_venv->SetWindowStyleFlag(wxBU_EXACTFIT);
+
+ auto* debug_button_clear_osc = new wxButton(debug_config_panel, ID_DEBUG_BUTTON_CLEAR_OSC, "Clear OSC configs");
+ debug_button_clear_osc->SetToolTip(
+ "No idea if this actually does anything valuable yet. I "
+ "think making certain animator changes (s.a. turning on "
+ "multi-byte character encoding) require you to reset "
+ "(i.e. delete) your OSC config. This button deletes all "
+ "your OSC configs.");
+ debug_button_clear_osc->SetWindowStyleFlag(wxBU_EXACTFIT);
+
+ auto* sizer = new wxBoxSizer(wxVERTICAL);
+ debug_config_panel->SetSizer(sizer);
+ sizer->Add(debug_button_list_pip, /*proportion=*/0, /*flags=*/wxEXPAND);
+ sizer->Add(debug_button_clear_pip, /*proportion=*/0, /*flags=*/wxEXPAND);
+ sizer->Add(debug_button_reset_venv, /*proportion=*/0, /*flags=*/wxEXPAND);
+ sizer->Add(debug_button_clear_osc, /*proportion=*/0, /*flags=*/wxEXPAND);
+ }
+
+ auto* sizer = new wxBoxSizer(wxHORIZONTAL);
+ debug_panel->SetSizer(sizer);
+ sizer->Add(debug_config_panel, /*proportion=*/0, /*flags=*/wxEXPAND);
+ sizer->Add(debug_out, /*proportion=*/1, /*flags=*/wxEXPAND);
+ }
+ debug_panel_->Hide();
+
auto* sizer = new wxBoxSizer(wxHORIZONTAL);
main_panel->SetSizer(sizer);
sizer->Add(navbar, /*proportion=*/0, /*flags=*/wxEXPAND);
sizer->Add(transcribe_panel, /*proportion=*/1, /*flags=*/wxEXPAND);
sizer->Add(unity_panel, /*proportion=*/1, /*flags=*/wxEXPAND);
+ sizer->Add(debug_panel, /*proportion=*/1, /*flags=*/wxEXPAND);
}
Bind(wxEVT_MENU, &Frame::OnExit, this, wxID_EXIT);
Bind(wxEVT_BUTTON, &Frame::OnNavbarTranscribe, this, ID_NAVBAR_BUTTON_TRANSCRIBE);
Bind(wxEVT_BUTTON, &Frame::OnNavbarUnity, this, ID_NAVBAR_BUTTON_UNITY);
+ Bind(wxEVT_BUTTON, &Frame::OnNavbarDebug, this, ID_NAVBAR_BUTTON_DEBUG);
Bind(wxEVT_BUTTON, &Frame::OnAppStart, this, ID_PY_APP_START_BUTTON);
Bind(wxEVT_BUTTON, &Frame::OnAppStop, this, ID_PY_APP_STOP_BUTTON);
Bind(wxEVT_TIMER, &Frame::OnAppDrain, this, ID_PY_APP_DRAIN);
Bind(wxEVT_BUTTON, &Frame::OnSetupPython, this, ID_PY_SETUP_BUTTON);
Bind(wxEVT_BUTTON, &Frame::OnDumpMics, this, ID_PY_DUMP_MICS_BUTTON);
Bind(wxEVT_BUTTON, &Frame::OnGenerateFX, this, ID_UNITY_BUTTON_GEN_ANIMATOR);
+ Bind(wxEVT_BUTTON, &Frame::OnListPip, this, ID_DEBUG_BUTTON_LIST_PIP);
+ Bind(wxEVT_BUTTON, &Frame::OnClearPip, this, ID_DEBUG_BUTTON_CLEAR_PIP);
+ Bind(wxEVT_BUTTON, &Frame::OnListPip, this, ID_DEBUG_BUTTON_LIST_PIP);
+ Bind(wxEVT_BUTTON, &Frame::OnResetVenv, this, ID_DEBUG_BUTTON_RESET_VENV);
+ Bind(wxEVT_BUTTON, &Frame::OnClearOSC, this, ID_DEBUG_BUTTON_CLEAR_OSC);
Bind(wxEVT_CHOICE, &Frame::OnUnityParamChange, this, ID_UNITY_CHARS_PER_SYNC);
Bind(wxEVT_CHOICE, &Frame::OnUnityParamChange, this, ID_UNITY_BYTES_PER_CHAR);
@@ -746,6 +827,7 @@ void Frame::OnNavbarTranscribe(wxCommandEvent& event) {
transcribe_panel_->Show();
unity_panel_->Hide();
+ debug_panel_->Hide();
Resize();
}
@@ -753,6 +835,15 @@ void Frame::OnNavbarUnity(wxCommandEvent& event) {
transcribe_panel_->Hide();
unity_panel_->Show();
+ debug_panel_->Hide();
+ Resize();
+}
+
+void Frame::OnNavbarDebug(wxCommandEvent& event)
+{
+ transcribe_panel_->Hide();
+ unity_panel_->Hide();
+ debug_panel_->Show();
Resize();
}
@@ -899,6 +990,79 @@ void Frame::OnGenerateFX(wxCommandEvent& event) }
}
+void Frame::OnListPip(wxCommandEvent& event)
+{
+ Log(debug_out_, "Listing pip packages... ");
+ PythonWrapper::InvokeWithArgs({
+ "-m pip",
+ "list",
+ }, "Failed to list pip packages", debug_out_);
+
+ Log(debug_out_, "Listing pip cache... ");
+ PythonWrapper::InvokeWithArgs({
+ "-m pip",
+ "cache",
+ "list",
+ }, "Failed to list pip cache", debug_out_);
+}
+
+void Frame::OnClearPip(wxCommandEvent& event)
+{
+ Log(debug_out_, "Clearing pip cache... ");
+ PythonWrapper::InvokeWithArgs({
+ "-m pip",
+ "cache",
+ "purge",
+ }, "Failed to clear pip cache", debug_out_);
+}
+
+void Frame::OnResetVenv(wxCommandEvent& event)
+{
+ Log(debug_out_, "Resetting virtual environment... ");
+
+ const std::string py_dir = "Resources/Python/Lib/site-packages";
+
+ if (!std::filesystem::is_directory(py_dir)) {
+ Log(debug_out_, "Python package directory not exist at {}, assuming "
+ "already deleted!\n", py_dir);
+ return;
+ }
+
+ std::error_code err;
+ if (std::filesystem::remove_all(py_dir, err)) {
+ Log(debug_out_, "success!\n");
+ }
+ else {
+ wxLogError("Failed to reset virtual environment: %s", err.message());
+ Log(debug_out_, "failed!\n");
+ }
+}
+
+void Frame::OnClearOSC(wxCommandEvent& event)
+{
+ std::filesystem::path osc_path = "C:/Users";
+ osc_path /= wxGetUserName().ToStdString();
+ osc_path /= "AppData/LocalLow/VRChat/vrchat/OSC";
+ osc_path = osc_path.lexically_normal();
+ Log(debug_out_, "OSC configs are stored at {}\n", osc_path.string());
+
+ if (!std::filesystem::is_directory(osc_path)) {
+ Log(debug_out_, "OSC configs do not exist at {}, assuming already "
+ "deleted!\n", osc_path.string());
+ return;
+ }
+
+ Log(debug_out_, "Deleting OSC configs... ");
+ std::error_code err;
+ if (std::filesystem::remove_all(osc_path, err)) {
+ Log(debug_out_, "success!\n");
+ }
+ else {
+ wxLogError("Failed to delete OSC configs: %s", err.message());
+ Log(debug_out_, "failed!\n");
+ }
+}
+
void Frame::OnUnityParamChangeImpl() {
int chars_per_sync_idx = unity_chars_per_sync_->GetSelection();
if (chars_per_sync_idx == wxNOT_FOUND) {
diff --git a/GUI/GUI/GUI/Frame.h b/GUI/GUI/GUI/Frame.h index 28c8f09..d179728 100644 --- a/GUI/GUI/GUI/Frame.h +++ b/GUI/GUI/GUI/Frame.h @@ -20,9 +20,11 @@ private: wxPanel* main_panel_;
wxPanel* transcribe_panel_;
wxPanel* unity_panel_;
+ wxPanel* debug_panel_;
wxTextCtrl* transcribe_out_;
wxTextCtrl* unity_out_;
+ wxTextCtrl* debug_out_;
wxTextCtrl* unity_animator_generated_dir_;
wxTextCtrl* unity_animator_generated_name_;
@@ -61,6 +63,7 @@ private: void OnExit(wxCommandEvent& event);
void OnNavbarTranscribe(wxCommandEvent& event);
void OnNavbarUnity(wxCommandEvent& event);
+ void OnNavbarDebug(wxCommandEvent& event);
void OnSetupPython(wxCommandEvent& event);
void OnDumpMics(wxCommandEvent& event);
void OnAppStart(wxCommandEvent& event);
@@ -70,6 +73,10 @@ private: void OnGenerateFX(wxCommandEvent& event);
void OnUnityParamChangeImpl();
void OnUnityParamChange(wxCommandEvent& event);
+ void OnListPip(wxCommandEvent& event);
+ void OnClearPip(wxCommandEvent& event);
+ void OnResetVenv(wxCommandEvent& event);
+ void OnClearOSC(wxCommandEvent& event);
void LoadAndSetIcons();
void Resize();
diff --git a/GUI/GUI/GUI/PythonWrapper.cpp b/GUI/GUI/GUI/PythonWrapper.cpp index 60437d2..2bf1a47 100644 --- a/GUI/GUI/GUI/PythonWrapper.cpp +++ b/GUI/GUI/GUI/PythonWrapper.cpp @@ -117,6 +117,30 @@ bool PythonWrapper::InvokeWithArgs(std::vector<std::string>&& args, std::move(args), py_stdout, py_stderr); } +bool PythonWrapper::InvokeWithArgs(std::vector<std::string>&& args, + const std::string&& err_msg, + wxTextCtrl* const out) { + std::string py_stdout, py_stderr; + if (InvokeWithArgs(std::move(args), &py_stdout, &py_stderr)) { + Log(out, "success!\n"); + Log(out, py_stdout.c_str()); + if (!py_stdout.empty()) { + Log(out, "\n"); + } + Log(out, py_stderr.c_str()); + if (!py_stderr.empty()) { + Log(out, "\n"); + } + return true; + } + else { + wxLogError("%s: %s", err_msg, py_stderr.c_str()); + Log(out, "failed!\n"); + return false; + } +} + + std::string PythonWrapper::GetVersion() { std::string py_stdout, py_stderr; bool ok = InvokeWithArgs({ "--version" }, &py_stdout, &py_stderr); @@ -214,28 +238,13 @@ bool PythonWrapper::GenerateAnimator( { Log(out, "Generating shader for {}x{} board (pass 0)...", config.rows, config.cols); - - std::string py_stdout, py_stderr; - if (InvokeWithArgs({ generate_shader_path, + if (!InvokeWithArgs({ generate_shader_path, "--bytes_per_char", std::to_string(config.bytes_per_char), "--rows", std::to_string(config.rows), "--cols", std::to_string(config.cols), "--shader_template", shader_template_path, "--shader_path", shader_path }, - &py_stdout, &py_stderr)) { - Log(out, "success!\n"); - Log(out, py_stdout.c_str()); - if (!py_stdout.empty()) { - Log(out, "\n"); - } - Log(out, py_stderr.c_str()); - if (!py_stderr.empty()) { - Log(out, "\n"); - } - } - else { - wxLogError("Failed to generate shader: %s", py_stderr.c_str()); - Log(out, "failed!\n"); + "Failed to generate shader", out)) { return false; } } @@ -243,26 +252,13 @@ bool PythonWrapper::GenerateAnimator( Log(out, "Generating shader for {}x{} board (pass 1)...", config.rows, config.cols); std::string py_stdout, py_stderr; - if (InvokeWithArgs({ generate_shader_path, + if (!InvokeWithArgs({ generate_shader_path, "--bytes_per_char", std::to_string(config.bytes_per_char), "--rows", std::to_string(config.rows), "--cols", std::to_string(config.cols), "--shader_template", shader_lighting_template_path, "--shader_path", shader_lighting_path }, - &py_stdout, &py_stderr)) { - Log(out, "success!\n"); - Log(out, py_stdout.c_str()); - if (!py_stdout.empty()) { - Log(out, "\n"); - } - Log(out, py_stderr.c_str()); - if (!py_stderr.empty()) { - Log(out, "\n"); - } - } - else { - wxLogError("Failed to generate shader: %s", py_stderr.c_str()); - Log(out, "failed!\n"); + "Failed to generate shader", out)) { return false; } } @@ -328,203 +324,89 @@ bool PythonWrapper::GenerateAnimator( } { Log(out, "Generating guid.map... "); - std::string py_stdout, py_stderr; - if (PythonWrapper::InvokeWithArgs({ libunity_path, "guid_map", + if (!InvokeWithArgs({ libunity_path, "guid_map", "--project_root", Quote(config.assets_path), "--save_to", Quote(guid_map_path), }, - &py_stdout, &py_stderr)) { - Log(out, "success!\n"); - Log(out, py_stdout.c_str()); - if (!py_stdout.empty()) { - Log(out, "\n"); - } - Log(out, py_stderr.c_str()); - if (!py_stderr.empty()) { - Log(out, "\n"); - } - } - else { - wxLogError("Failed to generate guid.map: %s", py_stderr.c_str()); - Log(out, "failed!\n"); + "Failed to generate guid.map", out)) { return false; } } { Log(out, "Generating animations... "); - std::string py_stdout, py_stderr; - if (InvokeWithArgs({ libtastt_path, "gen_anims", + if (!InvokeWithArgs({ libtastt_path, "gen_anims", "--gen_anim_dir", Quote(tastt_animations_path), "--guid_map", Quote(guid_map_path), "--chars_per_sync", std::to_string(config.chars_per_sync), "--bytes_per_char", std::to_string(config.bytes_per_char), "--rows", std::to_string(config.rows), "--cols", std::to_string(config.cols)}, - &py_stdout, &py_stderr)) { - Log(out, "success!\n"); - Log(out, py_stdout.c_str()); - if (!py_stdout.empty()) { - Log(out, "\n"); - } - Log(out, py_stderr.c_str()); - if (!py_stderr.empty()) { - Log(out, "\n"); - } - } - else { - wxLogError("Failed to generate animations: %s", py_stderr.c_str()); - Log(out, "failed!\n"); + "Failed to generate animations", out)) { return false; } } { Log(out, "Generating FX layer... "); - std::string py_stdout, py_stderr; - if (InvokeWithArgs({ libtastt_path, "gen_fx", + if (!InvokeWithArgs({ libtastt_path, "gen_fx", "--fx_dest", Quote(tastt_fx0_path), "--gen_anim_dir", Quote(tastt_animations_path), "--guid_map", Quote(guid_map_path), "--chars_per_sync", std::to_string(config.chars_per_sync), "--bytes_per_char", std::to_string(config.bytes_per_char), "--rows", std::to_string(config.rows), - "--cols", std::to_string(config.cols)}, - &py_stdout, &py_stderr)) { - Log(out, "success!\n"); - Log(out, py_stdout.c_str()); - if (!py_stdout.empty()) { - Log(out, "\n"); - } - Log(out, py_stderr.c_str()); - if (!py_stderr.empty()) { - Log(out, "\n"); - } - } - else { - wxLogError("Failed to generate FX layer: %s", py_stderr.c_str()); - Log(out, "failed!\n"); + "--cols", std::to_string(config.cols) }, + "Failed to generate FX layer", out)) { return false; } } { Log(out, "Adding enable/disable toggle... "); - std::string py_stdout, py_stderr; - if (InvokeWithArgs({ libunity_path, "add_toggle", + if (!InvokeWithArgs({ libunity_path, "add_toggle", "--fx0", Quote(tastt_fx0_path), "--fx_dest", Quote(tastt_fx1_path), "--gen_anim_dir", Quote(tastt_animations_path), "--guid_map", Quote(guid_map_path), }, - &py_stdout, &py_stderr)) { - Log(out, "success!\n"); - Log(out, py_stdout.c_str()); - if (!py_stdout.empty()) { - Log(out, "\n"); - } - Log(out, py_stderr.c_str()); - if (!py_stderr.empty()) { - Log(out, "\n"); - } - } - else { - wxLogError("Failed to add enable/disable toggle: %s", py_stderr.c_str()); - Log(out, "failed!\n"); + "Failed to add enable/disable toggle", out)) { return false; } } { Log(out, "Merging with user animator... "); - std::string py_stdout, py_stderr; - if (InvokeWithArgs({ libunity_path, "merge", + if (!InvokeWithArgs({ libunity_path, "merge", "--fx0", Quote(config.fx_path), "--fx1", Quote(tastt_fx1_path), "--fx_dest", Quote(tastt_fx2_path), }, - &py_stdout, &py_stderr)) { - Log(out, "success!\n"); - Log(out, py_stdout.c_str()); - if (!py_stdout.empty()) { - Log(out, "\n"); - } - Log(out, py_stderr.c_str()); - if (!py_stderr.empty()) { - Log(out, "\n"); - } - } - else { - wxLogError("Failed to merge animators: %s", py_stderr.c_str()); - Log(out, "failed!\n"); + "Failed to merge animators", out)) { return false; } } { Log(out, "Setting noop animations... "); - std::string py_stdout, py_stderr; - if (InvokeWithArgs({ libunity_path, "set_noop_anim", + if (!InvokeWithArgs({ libunity_path, "set_noop_anim", "--fx0", Quote(tastt_fx2_path), "--fx_dest", Quote(tastt_animator_path), "--gen_anim_dir", Quote(tastt_animations_path), "--guid_map", Quote(guid_map_path), }, - &py_stdout, &py_stderr)) { - Log(out, "success!\n"); - Log(out, py_stdout.c_str()); - if (!py_stdout.empty()) { - Log(out, "\n"); - } - Log(out, py_stderr.c_str()); - if (!py_stderr.empty()) { - Log(out, "\n"); - } - } - else { - wxLogError("Failed to set noop animations: %s", py_stderr.c_str()); - Log(out, "failed!\n"); + "Failed to set noop animations", out)) { return false; } } { Log(out, "Generating avatar parameters... "); - std::string py_stdout, py_stderr; - if (InvokeWithArgs({ generate_params_path, + if (!InvokeWithArgs({ generate_params_path, "--old_params", Quote(config.params_path), "--new_params", Quote(tastt_params_path), "--chars_per_sync", std::to_string(config.chars_per_sync), "--bytes_per_char", std::to_string(config.bytes_per_char) }, - &py_stdout, &py_stderr)) { - Log(out, "success!\n"); - Log(out, py_stdout.c_str()); - if (!py_stdout.empty()) { - Log(out, "\n"); - } - Log(out, py_stderr.c_str()); - if (!py_stderr.empty()) { - Log(out, "\n"); - } - } - else { - wxLogError("Failed to generate avatar parameters: %s", py_stderr.c_str()); - Log(out, "failed!\n"); + "Failed to generate avatar parameters", out)) { return false; } } { Log(out, "Generating avatar menu... "); - std::string py_stdout, py_stderr; - // No idea why, but inlining this into `InvokeWithArgs` confuses the compiler. - std::vector<std::string> args = { generate_menu_path, + if (!InvokeWithArgs({ generate_menu_path, "--old_menu", Quote(config.menu_path), - "--new_menu", Quote(tastt_menu_path), }; - if (InvokeWithArgs( std::move(args), - &py_stdout, &py_stderr)) { - Log(out, "success!\n"); - Log(out, py_stdout.c_str()); - if (!py_stdout.empty()) { - Log(out, "\n"); - } - Log(out, py_stderr.c_str()); - if (!py_stderr.empty()) { - Log(out, "\n"); - } - } - else { - wxLogError("Failed to generate avatar menu: %s", py_stderr.c_str()); - Log(out, "failed!\n"); + "--new_menu", Quote(tastt_menu_path) }, + "Failed to generate avatar menu", out)) { return false; } } diff --git a/GUI/GUI/GUI/PythonWrapper.h b/GUI/GUI/GUI/PythonWrapper.h index c28a1f1..4ae4583 100644 --- a/GUI/GUI/GUI/PythonWrapper.h +++ b/GUI/GUI/GUI/PythonWrapper.h @@ -37,6 +37,9 @@ namespace PythonWrapper bool InvokeWithArgs(std::vector<std::string>&& args, std::string* py_stdout, std::string* py_stderr = NULL); + bool InvokeWithArgs(std::vector<std::string>&& args, + const std::string&& err_msg, wxTextCtrl* out); + // Execute python --version. std::string GetVersion(); |
