starting prusaslicer from gcode viewer and vice versa, by menus or by stl drop on icon. Bring gcode viewer forward after start.

This commit is contained in:
David Kocik 2020-10-12 13:44:08 +02:00
parent 92b2d624a4
commit 4b224359ef
9 changed files with 143 additions and 64 deletions

View file

@ -838,7 +838,6 @@ bool GUI_App::on_init_inner()
if (! plater_) if (! plater_)
return; return;
//m_other_instance_message_handler->report();
if (app_config->dirty() && app_config->get("autosave") == "1") if (app_config->dirty() && app_config->get("autosave") == "1")
app_config->save(); app_config->save();
@ -861,6 +860,7 @@ bool GUI_App::on_init_inner()
static bool once = true; static bool once = true;
if (once) { if (once) {
once = false; once = false;
#if ENABLE_GCODE_VIEWER #if ENABLE_GCODE_VIEWER
if (preset_updater != nullptr) { if (preset_updater != nullptr) {
#endif // ENABLE_GCODE_VIEWER #endif // ENABLE_GCODE_VIEWER
@ -904,6 +904,10 @@ bool GUI_App::on_init_inner()
update_mode(); // update view mode after fix of the object_list size update_mode(); // update view mode after fix of the object_list size
#ifdef __APPLE__
other_instance_message_handler()->bring_instance_forward();
#endif //__APPLE__
m_initialized = true; m_initialized = true;
return true; return true;
} }
@ -1714,6 +1718,10 @@ void GUI_App::OSXStoreOpenFiles(const wxArrayString &fileNames)
// Opening PrusaSlicer by drag & dropping a G-Code onto PrusaSlicer icon in Finder, // Opening PrusaSlicer by drag & dropping a G-Code onto PrusaSlicer icon in Finder,
// just G-codes were passed. Switch to G-code viewer mode. // just G-codes were passed. Switch to G-code viewer mode.
m_app_mode = EAppMode::GCodeViewer; m_app_mode = EAppMode::GCodeViewer;
if(app_config != nullptr)
delete app_config;
app_config = nullptr;
init_app_config();
} }
wxApp::OSXStoreOpenFiles(fileNames); wxApp::OSXStoreOpenFiles(fileNames);
} }
@ -1722,18 +1730,24 @@ void GUI_App::MacOpenFiles(const wxArrayString &fileNames)
{ {
std::vector<std::string> files; std::vector<std::string> files;
std::vector<wxString> gcode_files; std::vector<wxString> gcode_files;
std::vector<wxString> non_gcode_files;
for (const auto& filename : fileNames) { for (const auto& filename : fileNames) {
wxString fn = filename.Upper(); wxString fn = filename.Upper();
if (fn.EndsWith(".G") || fn.EndsWith(".GCODE")) if (fn.EndsWith(".G") || fn.EndsWith(".GCODE"))
gcode_files.emplace_back(filename); gcode_files.emplace_back(filename);
else else {
files.emplace_back(into_u8(filename)); files.emplace_back(into_u8(filename));
non_gcode_files.emplace_back(filename);
}
} }
if (m_app_mode == EAppMode::GCodeViewer) { if (m_app_mode == EAppMode::GCodeViewer) {
// Running in G-code viewer. // Running in G-code viewer.
// Load the first G-code into the G-code viewer. // Load the first G-code into the G-code viewer.
// Or if no G-codes, send other files to slicer.
if (! gcode_files.empty()) if (! gcode_files.empty())
this->plater()->load_gcode(gcode_files.front()); this->plater()->load_gcode(gcode_files.front());
if (!non_gcode_files.empty())
start_new_slicer(non_gcode_files, true);
} else { } else {
if (! files.empty()) if (! files.empty())
this->plater()->load_files(files, true, true); this->plater()->load_files(files, true, true);

View file

@ -89,6 +89,8 @@ private:
void unregister_for_messages(); void unregister_for_messages();
// Opaque pointer to RemovableDriveManagerMM // Opaque pointer to RemovableDriveManagerMM
void* m_impl_osx; void* m_impl_osx;
public:
void bring_instance_forward();
#endif //__APPLE__ #endif //__APPLE__
}; };

View file

@ -5,4 +5,5 @@
-(instancetype) init; -(instancetype) init;
-(void) add_observer:(NSString *)version; -(void) add_observer:(NSString *)version;
-(void) message_update:(NSNotification *)note; -(void) message_update:(NSNotification *)note;
-(void) bring_forward;
@end @end

View file

@ -20,6 +20,13 @@
-(void)message_update:(NSNotification *)msg -(void)message_update:(NSNotification *)msg
{ {
//NSLog(@"recieved msg %@", msg); //NSLog(@"recieved msg %@", msg);
[self bring_forward];
//pass message
Slic3r::GUI::wxGetApp().other_instance_message_handler()->handle_message(std::string([msg.userInfo[@"data"] UTF8String]));
}
-(void) bring_forward
{
//demiaturize all windows //demiaturize all windows
for(NSWindow* win in [NSApp windows]) for(NSWindow* win in [NSApp windows])
{ {
@ -30,8 +37,6 @@
} }
//bring window to front //bring window to front
[[NSApplication sharedApplication] activateIgnoringOtherApps : YES]; [[NSApplication sharedApplication] activateIgnoringOtherApps : YES];
//pass message
Slic3r::GUI::wxGetApp().other_instance_message_handler()->handle_message(std::string([msg.userInfo[@"data"] UTF8String]));
} }
@end @end
@ -67,6 +72,13 @@ void OtherInstanceMessageHandler::unregister_for_messages()
NSLog(@"warning: unregister instance InstanceCheck notifications not required"); NSLog(@"warning: unregister instance InstanceCheck notifications not required");
} }
} }
void OtherInstanceMessageHandler::bring_instance_forward()
{
if (m_impl_osx) {
[m_impl_osx bring_forward];
}
}
}//namespace GUI }//namespace GUI
}//namespace Slicer }//namespace Slicer

View file

@ -68,15 +68,15 @@ class GCodeViewerTaskBarIcon : public wxTaskBarIcon
{ {
public: public:
GCodeViewerTaskBarIcon(wxTaskBarIconType iconType = wxTBI_DEFAULT_TYPE) : wxTaskBarIcon(iconType) {} GCodeViewerTaskBarIcon(wxTaskBarIconType iconType = wxTBI_DEFAULT_TYPE) : wxTaskBarIcon(iconType) {}
#if 0
wxMenu *CreatePopupMenu() override { wxMenu *CreatePopupMenu() override {
wxMenu *menu = new wxMenu; wxMenu *menu = new wxMenu;
int id; //int id;
auto *item = menu->Append(id = wxNewId(), "&Test menu"); //auto *item = menu->Append(id = wxNewId(), "&Test menu");
menu->Bind(wxEVT_MENU, [this](wxCommandEvent &) { wxMessageBox("Test menu - GCode Viewer"); }, id); //menu->Bind(wxEVT_MENU, [this](wxCommandEvent &) { wxMessageBox("Test menu - GCode Viewer"); }, id);
append_menu_item(menu, wxID_ANY, _(L("Open PrusaSlicer")), _(L("")),
[this](wxCommandEvent&) { start_new_slicer(nullptr, true); }, "", nullptr);
return menu; return menu;
} }
#endif
}; };
#endif // __APPLE__ #endif // __APPLE__
@ -1258,7 +1258,8 @@ void MainFrame::init_menubar()
windowMenu->AppendSeparator(); windowMenu->AppendSeparator();
append_menu_item(windowMenu, wxID_ANY, _(L("Open new instance")) + "\tCtrl+I", _(L("Open a new PrusaSlicer instance")), append_menu_item(windowMenu, wxID_ANY, _(L("Open new instance")) + "\tCtrl+I", _(L("Open a new PrusaSlicer instance")),
[this](wxCommandEvent&) { start_new_slicer(); }, "", nullptr); [this](wxCommandEvent&) { start_new_slicer(); }, "", nullptr, [this]() {return m_plater != nullptr && wxGetApp().app_config->get("single_instance") != "1"; }, this);
} }
// View menu // View menu
@ -1392,6 +1393,9 @@ void MainFrame::init_menubar_as_gcodeviewer()
append_menu_item(fileMenu, wxID_ANY, _L("Export &toolpaths as OBJ") + dots, _L("Export toolpaths as OBJ"), append_menu_item(fileMenu, wxID_ANY, _L("Export &toolpaths as OBJ") + dots, _L("Export toolpaths as OBJ"),
[this](wxCommandEvent&) { if (m_plater != nullptr) m_plater->export_toolpaths_to_obj(); }, "export_plater", nullptr, [this](wxCommandEvent&) { if (m_plater != nullptr) m_plater->export_toolpaths_to_obj(); }, "export_plater", nullptr,
[this]() {return can_export_toolpaths(); }, this); [this]() {return can_export_toolpaths(); }, this);
append_menu_item(fileMenu, wxID_ANY, _L("Open &PrusaSlicer") + dots, _L("Open PrusaSlicer"),
[this](wxCommandEvent&) { start_new_slicer(); }, "", nullptr,
[this]() {return true; }, this);
fileMenu->AppendSeparator(); fileMenu->AppendSeparator();
append_menu_item(fileMenu, wxID_EXIT, _L("&Quit"), wxString::Format(_L("Quit %s"), SLIC3R_APP_NAME), append_menu_item(fileMenu, wxID_EXIT, _L("&Quit"), wxString::Format(_L("Quit %s"), SLIC3R_APP_NAME),
[this](wxCommandEvent&) { Close(false); }); [this](wxCommandEvent&) { Close(false); });

View file

@ -1409,7 +1409,7 @@ bool PlaterDropTarget::OnDropFiles(wxCoord x, wxCoord y, const wxArrayString &fi
else if (paths.size() == 1) { else if (paths.size() == 1) {
plater->load_gcode(from_path(paths.front())); plater->load_gcode(from_path(paths.front()));
return true; return true;
} }
return false; return false;
} }
#endif // ENABLE_GCODE_VIEWER #endif // ENABLE_GCODE_VIEWER
@ -1759,6 +1759,8 @@ struct Plater::priv
void msw_rescale_object_menu(); void msw_rescale_object_menu();
void bring_instance_forward() const;
// returns the path to project file with the given extension (none if extension == wxEmptyString) // returns the path to project file with the given extension (none if extension == wxEmptyString)
// extension should contain the leading dot, i.e.: ".3mf" // extension should contain the leading dot, i.e.: ".3mf"
wxString get_project_filename(const wxString& extension = wxEmptyString) const; wxString get_project_filename(const wxString& extension = wxEmptyString) const;
@ -2040,23 +2042,7 @@ Plater::priv::priv(Plater *q, MainFrame *main_frame)
this->load_files(evt.data, true, true); this->load_files(evt.data, true, true);
}); });
this->q->Bind(EVT_INSTANCE_GO_TO_FRONT, [this](InstanceGoToFrontEvent &) { this->q->Bind(EVT_INSTANCE_GO_TO_FRONT, [this](InstanceGoToFrontEvent &) {
BOOST_LOG_TRIVIAL(debug) << "prusaslicer window going forward"; bring_instance_forward();
//this code maximize app window on Fedora
{
wxGetApp().mainframe->Iconize(false);
if (wxGetApp().mainframe->IsMaximized())
wxGetApp().mainframe->Maximize(true);
else
wxGetApp().mainframe->Maximize(false);
}
//this code maximize window on Ubuntu
{
wxGetApp().mainframe->Restore();
wxGetApp().GetTopWindow()->SetFocus(); // focus on my window
wxGetApp().GetTopWindow()->Raise(); // bring window to front
wxGetApp().GetTopWindow()->Show(true); // show the window
}
}); });
wxGetApp().other_instance_message_handler()->init(this->q); wxGetApp().other_instance_message_handler()->init(this->q);
@ -4545,6 +4531,34 @@ void Plater::priv::update_after_undo_redo(const UndoRedo::Snapshot& snapshot, bo
BOOST_LOG_TRIVIAL(info) << "Undo / Redo snapshot reloaded. Undo / Redo stack memory: " << Slic3r::format_memsize_MB(this->undo_redo_stack().memsize()) << log_memory_info(); BOOST_LOG_TRIVIAL(info) << "Undo / Redo snapshot reloaded. Undo / Redo stack memory: " << Slic3r::format_memsize_MB(this->undo_redo_stack().memsize()) << log_memory_info();
} }
void Plater::priv::bring_instance_forward() const
{
#ifdef __APPLE__
wxGetApp().other_instance_message_handler()->bring_instance_forward();
return;
#endif //__APPLE__
if (main_frame == nullptr) {
BOOST_LOG_TRIVIAL(debug) << "Couldnt bring instance forward - mainframe is null";
return;
}
BOOST_LOG_TRIVIAL(debug) << "prusaslicer window going forward";
//this code maximize app window on Fedora
{
main_frame->Iconize(false);
if (main_frame->IsMaximized())
main_frame->Maximize(true);
else
main_frame->Maximize(false);
}
//this code maximize window on Ubuntu
{
main_frame->Restore();
wxGetApp().GetTopWindow()->SetFocus(); // focus on my window
wxGetApp().GetTopWindow()->Raise(); // bring window to front
wxGetApp().GetTopWindow()->Show(true); // show the window
}
}
void Sidebar::set_btn_label(const ActionButtonType btn_type, const wxString& label) const void Sidebar::set_btn_label(const ActionButtonType btn_type, const wxString& label) const
{ {
switch (btn_type) switch (btn_type)
@ -6016,6 +6030,10 @@ bool Plater::PopupMenu(wxMenu *menu, const wxPoint& pos)
} }
return out; return out;
} }
void Plater::bring_instance_forward()
{
p->bring_instance_forward();
}
SuppressBackgroundProcessingUpdate::SuppressBackgroundProcessingUpdate() : SuppressBackgroundProcessingUpdate::SuppressBackgroundProcessingUpdate() :
m_was_scheduled(wxGetApp().plater()->is_background_process_update_scheduled()) m_was_scheduled(wxGetApp().plater()->is_background_process_update_scheduled())

View file

@ -333,6 +333,8 @@ public:
const NotificationManager* get_notification_manager() const; const NotificationManager* get_notification_manager() const;
NotificationManager* get_notification_manager(); NotificationManager* get_notification_manager();
void bring_instance_forward();
// ROII wrapper for suppressing the Undo / Redo snapshot to be taken. // ROII wrapper for suppressing the Undo / Redo snapshot to be taken.
class SuppressSnapshots class SuppressSnapshots
{ {

View file

@ -33,7 +33,7 @@ enum class NewSlicerInstanceType {
// Start a new Slicer process instance either in a Slicer mode or in a G-code mode. // Start a new Slicer process instance either in a Slicer mode or in a G-code mode.
// Optionally load a 3MF, STL or a G-code on start. // Optionally load a 3MF, STL or a G-code on start.
static void start_new_slicer_or_gcodeviewer(const NewSlicerInstanceType instance_type, const wxString *path_to_open) static void start_new_slicer_or_gcodeviewer(const NewSlicerInstanceType instance_type, const std::vector<wxString> paths_to_open, bool single_instance)
{ {
#ifdef _WIN32 #ifdef _WIN32
wxString path; wxString path;
@ -41,10 +41,14 @@ static void start_new_slicer_or_gcodeviewer(const NewSlicerInstanceType instance
path += "\\"; path += "\\";
path += (instance_type == NewSlicerInstanceType::Slicer) ? "prusa-slicer.exe" : "prusa-gcodeviewer.exe"; path += (instance_type == NewSlicerInstanceType::Slicer) ? "prusa-slicer.exe" : "prusa-gcodeviewer.exe";
std::vector<const wchar_t*> args; std::vector<const wchar_t*> args;
args.reserve(3); args.reserve(4);
args.emplace_back(path.wc_str()); args.emplace_back(path.wc_str());
if (path_to_open != nullptr) if (!paths_to_open.empty()) {
args.emplace_back(path_to_open->wc_str()); for (const auto& file : paths_to_open)
args.emplace_back(file);
}
if (instance_type == NewSlicerInstanceType::Slicer && single_instance)
args.emplace_back(L"--single-instance");
args.emplace_back(nullptr); args.emplace_back(nullptr);
BOOST_LOG_TRIVIAL(info) << "Trying to spawn a new slicer \"" << into_u8(path) << "\""; BOOST_LOG_TRIVIAL(info) << "Trying to spawn a new slicer \"" << into_u8(path) << "\"";
// Don't call with wxEXEC_HIDE_CONSOLE, PrusaSlicer in GUI mode would just show the splash screen. It would not open the main window though, it would // Don't call with wxEXEC_HIDE_CONSOLE, PrusaSlicer in GUI mode would just show the splash screen. It would not open the main window though, it would
@ -53,72 +57,92 @@ static void start_new_slicer_or_gcodeviewer(const NewSlicerInstanceType instance
BOOST_LOG_TRIVIAL(error) << "Failed to spawn a new slicer \"" << into_u8(path); BOOST_LOG_TRIVIAL(error) << "Failed to spawn a new slicer \"" << into_u8(path);
#else #else
// Own executable path. // Own executable path.
boost::filesystem::path bin_path = into_path(wxStandardPaths::Get().GetExecutablePath()); boost::filesystem::path bin_path = into_path(wxStandardPaths::Get().GetExecutablePath());
#if defined(__APPLE__) #if defined(__APPLE__)
{ {
// Maybe one day we will be able to run PrusaGCodeViewer, but for now the Apple notarization // Maybe one day we will be able to run PrusaGCodeViewer, but for now the Apple notarization
// process refuses Apps with multiple binaries and Vojtech does not know any workaround. // process refuses Apps with multiple binaries and Vojtech does not know any workaround.
// ((instance_type == NewSlicerInstanceType::Slicer) ? "PrusaSlicer" : "PrusaGCodeViewer"); // ((instance_type == NewSlicerInstanceType::Slicer) ? "PrusaSlicer" : "PrusaGCodeViewer");
// Just run PrusaSlicer and give it a --gcodeviewer parameter. // Just run PrusaSlicer and give it a --gcodeviewer parameter.
bin_path = bin_path.parent_path() / "PrusaSlicer"; bin_path = bin_path.parent_path() / "PrusaSlicer";
// On Apple the wxExecute fails, thus we use boost::process instead. // On Apple the wxExecute fails, thus we use boost::process instead.
BOOST_LOG_TRIVIAL(info) << "Trying to spawn a new slicer \"" << bin_path.string() << "\""; BOOST_LOG_TRIVIAL(info) << "Trying to spawn a new slicer \"" << bin_path.string() << "\"";
try { try {
std::vector<std::string> args; std::vector<std::string> args;
if (instance_type == NewSlicerInstanceType::GCodeViewer) if (instance_type == NewSlicerInstanceType::GCodeViewer)
args.emplace_back("--gcodeviewer"); args.emplace_back("--gcodeviewer");
if (path_to_open) if (!paths_to_open.empty()) {
args.emplace_back(into_u8(*path_to_open)); for (const auto& file : paths_to_open)
boost::process::spawn(bin_path, args); args.emplace_back(into_u8(file));
} catch (const std::exception &ex) { }
if (instance_type == NewSlicerInstanceType::Slicer && single_instance)
args.emplace_back("--single-instance");
boost::process::spawn(bin_path, args);
}
catch (const std::exception& ex) {
BOOST_LOG_TRIVIAL(error) << "Failed to spawn a new slicer \"" << bin_path.string() << "\": " << ex.what(); BOOST_LOG_TRIVIAL(error) << "Failed to spawn a new slicer \"" << bin_path.string() << "\": " << ex.what();
} }
} }
#else // Linux or Unix #else // Linux or Unix
{ {
std::vector<const char*> args; std::vector<const char*> args;
args.reserve(3); args.reserve(3);
#ifdef __linux #ifdef __linux
static const char *gcodeviewer_param = "--gcodeviewer"; static const char* gcodeviewer_param = "--gcodeviewer";
{ {
// If executed by an AppImage, start the AppImage, not the main process. // If executed by an AppImage, start the AppImage, not the main process.
// see https://docs.appimage.org/packaging-guide/environment-variables.html#id2 // see https://docs.appimage.org/packaging-guide/environment-variables.html#id2
const char *appimage_binary = std::getenv("APPIMAGE"); const char* appimage_binary = std::getenv("APPIMAGE");
if (appimage_binary) { if (appimage_binary) {
args.emplace_back(appimage_binary); args.emplace_back(appimage_binary);
if (instance_type == NewSlicerInstanceType::GCodeViewer) if (instance_type == NewSlicerInstanceType::GCodeViewer)
args.emplace_back(gcodeviewer_param); args.emplace_back(gcodeviewer_param);
} }
} }
#endif // __linux #endif // __linux
std::string my_path; std::string my_path;
if (args.empty()) { if (args.empty()) {
// Binary path was not set to the AppImage in the Linux specific block above, call the application directly. // Binary path was not set to the AppImage in the Linux specific block above, call the application directly.
my_path = (bin_path.parent_path() / ((instance_type == NewSlicerInstanceType::Slicer) ? "prusa-slicer" : "prusa-gcodeviewer")).string(); my_path = (bin_path.parent_path() / ((instance_type == NewSlicerInstanceType::Slicer) ? "prusa-slicer" : "prusa-gcodeviewer")).string();
args.emplace_back(my_path.c_str()); args.emplace_back(my_path.c_str());
} }
std::string to_open; std::string to_open;
if (path_to_open) { if (!paths_to_open.empty()) {
to_open = into_u8(*path_to_open); for (const auto& file : paths_to_open) {
args.emplace_back(to_open.c_str()); to_open = into_u8(file);
} args.emplace_back(to_open.c_str());
args.emplace_back(nullptr); }
}
if (instance_type == NewSlicerInstanceType::Slicer && single_instance)
args.emplace_back("--single-instance");
args.emplace_back(nullptr);
BOOST_LOG_TRIVIAL(info) << "Trying to spawn a new slicer \"" << args[0] << "\""; BOOST_LOG_TRIVIAL(info) << "Trying to spawn a new slicer \"" << args[0] << "\"";
if (wxExecute(const_cast<char**>(args.data()), wxEXEC_ASYNC | wxEXEC_MAKE_GROUP_LEADER) <= 0) if (wxExecute(const_cast<char**>(args.data()), wxEXEC_ASYNC | wxEXEC_MAKE_GROUP_LEADER) <= 0)
BOOST_LOG_TRIVIAL(error) << "Failed to spawn a new slicer \"" << args[0]; BOOST_LOG_TRIVIAL(error) << "Failed to spawn a new slicer \"" << args[0];
} }
#endif // Linux or Unix #endif // Linux or Unix
#endif // Win32 #endif // Win32
} }
static void start_new_slicer_or_gcodeviewer(const NewSlicerInstanceType instance_type, const wxString* path_to_open, bool single_instance)
void start_new_slicer(const wxString *path_to_open)
{ {
start_new_slicer_or_gcodeviewer(NewSlicerInstanceType::Slicer, path_to_open); std::vector<wxString> paths;
if (path_to_open != nullptr)
paths.emplace_back(path_to_open->wc_str());
start_new_slicer_or_gcodeviewer(instance_type, paths, single_instance);
}
void start_new_slicer(const wxString *path_to_open, bool single_instance)
{
start_new_slicer_or_gcodeviewer(NewSlicerInstanceType::Slicer, path_to_open, single_instance);
}
void start_new_slicer(const std::vector<wxString>& files, bool single_instance)
{
start_new_slicer_or_gcodeviewer(NewSlicerInstanceType::Slicer, files, single_instance);
} }
void start_new_gcodeviewer(const wxString *path_to_open) void start_new_gcodeviewer(const wxString *path_to_open)
{ {
start_new_slicer_or_gcodeviewer(NewSlicerInstanceType::GCodeViewer, path_to_open); start_new_slicer_or_gcodeviewer(NewSlicerInstanceType::GCodeViewer, path_to_open, false);
} }
void start_new_gcodeviewer_open_file(wxWindow *parent) void start_new_gcodeviewer_open_file(wxWindow *parent)

View file

@ -8,7 +8,9 @@ namespace Slic3r {
namespace GUI { namespace GUI {
// Start a new slicer instance, optionally with a file to open. // Start a new slicer instance, optionally with a file to open.
void start_new_slicer(const wxString *path_to_open = nullptr); void start_new_slicer(const wxString *path_to_open = nullptr, bool single_instance = false);
void start_new_slicer(const std::vector<wxString>& files, bool single_instance = false);
// Start a new G-code viewer instance, optionally with a file to open. // Start a new G-code viewer instance, optionally with a file to open.
void start_new_gcodeviewer(const wxString *path_to_open = nullptr); void start_new_gcodeviewer(const wxString *path_to_open = nullptr);
// Open a file dialog, ask the user to select a new G-code to open, start a new G-code viewer. // Open a file dialog, ask the user to select a new G-code to open, start a new G-code viewer.