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_)
return;
//m_other_instance_message_handler->report();
if (app_config->dirty() && app_config->get("autosave") == "1")
app_config->save();
@ -861,6 +860,7 @@ bool GUI_App::on_init_inner()
static bool once = true;
if (once) {
once = false;
#if ENABLE_GCODE_VIEWER
if (preset_updater != nullptr) {
#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
#ifdef __APPLE__
other_instance_message_handler()->bring_instance_forward();
#endif //__APPLE__
m_initialized = 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,
// just G-codes were passed. Switch to G-code viewer mode.
m_app_mode = EAppMode::GCodeViewer;
if(app_config != nullptr)
delete app_config;
app_config = nullptr;
init_app_config();
}
wxApp::OSXStoreOpenFiles(fileNames);
}
@ -1722,18 +1730,24 @@ void GUI_App::MacOpenFiles(const wxArrayString &fileNames)
{
std::vector<std::string> files;
std::vector<wxString> gcode_files;
std::vector<wxString> non_gcode_files;
for (const auto& filename : fileNames) {
wxString fn = filename.Upper();
if (fn.EndsWith(".G") || fn.EndsWith(".GCODE"))
gcode_files.emplace_back(filename);
else
else {
files.emplace_back(into_u8(filename));
non_gcode_files.emplace_back(filename);
}
}
if (m_app_mode == EAppMode::GCodeViewer) {
// Running in 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())
this->plater()->load_gcode(gcode_files.front());
if (!non_gcode_files.empty())
start_new_slicer(non_gcode_files, true);
} else {
if (! files.empty())
this->plater()->load_files(files, true, true);

View File

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

View File

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

View File

@ -20,6 +20,13 @@
-(void)message_update:(NSNotification *)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
for(NSWindow* win in [NSApp windows])
{
@ -30,8 +37,6 @@
}
//bring window to front
[[NSApplication sharedApplication] activateIgnoringOtherApps : YES];
//pass message
Slic3r::GUI::wxGetApp().other_instance_message_handler()->handle_message(std::string([msg.userInfo[@"data"] UTF8String]));
}
@end
@ -67,6 +72,13 @@ void OtherInstanceMessageHandler::unregister_for_messages()
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 Slicer

View File

@ -68,15 +68,15 @@ class GCodeViewerTaskBarIcon : public wxTaskBarIcon
{
public:
GCodeViewerTaskBarIcon(wxTaskBarIconType iconType = wxTBI_DEFAULT_TYPE) : wxTaskBarIcon(iconType) {}
#if 0
wxMenu *CreatePopupMenu() override {
wxMenu *menu = new wxMenu;
int id;
auto *item = menu->Append(id = wxNewId(), "&Test menu");
menu->Bind(wxEVT_MENU, [this](wxCommandEvent &) { wxMessageBox("Test menu - GCode Viewer"); }, id);
//int id;
//auto *item = menu->Append(id = wxNewId(), "&Test menu");
//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;
}
#endif
};
#endif // __APPLE__
@ -1258,7 +1258,8 @@ void MainFrame::init_menubar()
windowMenu->AppendSeparator();
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
@ -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"),
[this](wxCommandEvent&) { if (m_plater != nullptr) m_plater->export_toolpaths_to_obj(); }, "export_plater", nullptr,
[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();
append_menu_item(fileMenu, wxID_EXIT, _L("&Quit"), wxString::Format(_L("Quit %s"), SLIC3R_APP_NAME),
[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) {
plater->load_gcode(from_path(paths.front()));
return true;
}
}
return false;
}
#endif // ENABLE_GCODE_VIEWER
@ -1759,6 +1759,8 @@ struct Plater::priv
void msw_rescale_object_menu();
void bring_instance_forward() const;
// returns the path to project file with the given extension (none if extension == wxEmptyString)
// extension should contain the leading dot, i.e.: ".3mf"
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->q->Bind(EVT_INSTANCE_GO_TO_FRONT, [this](InstanceGoToFrontEvent &) {
BOOST_LOG_TRIVIAL(debug) << "prusaslicer window going 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
}
bring_instance_forward();
});
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();
}
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
{
switch (btn_type)
@ -6016,6 +6030,10 @@ bool Plater::PopupMenu(wxMenu *menu, const wxPoint& pos)
}
return out;
}
void Plater::bring_instance_forward()
{
p->bring_instance_forward();
}
SuppressBackgroundProcessingUpdate::SuppressBackgroundProcessingUpdate() :
m_was_scheduled(wxGetApp().plater()->is_background_process_update_scheduled())

View File

@ -333,6 +333,8 @@ public:
const NotificationManager* get_notification_manager() const;
NotificationManager* get_notification_manager();
void bring_instance_forward();
// ROII wrapper for suppressing the Undo / Redo snapshot to be taken.
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.
// 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
wxString path;
@ -41,10 +41,14 @@ static void start_new_slicer_or_gcodeviewer(const NewSlicerInstanceType instance
path += "\\";
path += (instance_type == NewSlicerInstanceType::Slicer) ? "prusa-slicer.exe" : "prusa-gcodeviewer.exe";
std::vector<const wchar_t*> args;
args.reserve(3);
args.reserve(4);
args.emplace_back(path.wc_str());
if (path_to_open != nullptr)
args.emplace_back(path_to_open->wc_str());
if (!paths_to_open.empty()) {
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);
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
@ -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);
#else
// Own executable path.
boost::filesystem::path bin_path = into_path(wxStandardPaths::Get().GetExecutablePath());
#if defined(__APPLE__)
boost::filesystem::path bin_path = into_path(wxStandardPaths::Get().GetExecutablePath());
#if defined(__APPLE__)
{
// 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.
// ((instance_type == NewSlicerInstanceType::Slicer) ? "PrusaSlicer" : "PrusaGCodeViewer");
// 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.
BOOST_LOG_TRIVIAL(info) << "Trying to spawn a new slicer \"" << bin_path.string() << "\"";
try {
std::vector<std::string> args;
if (instance_type == NewSlicerInstanceType::GCodeViewer)
args.emplace_back("--gcodeviewer");
if (path_to_open)
args.emplace_back(into_u8(*path_to_open));
boost::process::spawn(bin_path, args);
} catch (const std::exception &ex) {
std::vector<std::string> args;
if (instance_type == NewSlicerInstanceType::GCodeViewer)
args.emplace_back("--gcodeviewer");
if (!paths_to_open.empty()) {
for (const auto& file : paths_to_open)
args.emplace_back(into_u8(file));
}
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();
}
}
}
#else // Linux or Unix
#else // Linux or Unix
{
std::vector<const char*> args;
args.reserve(3);
#ifdef __linux
static const char *gcodeviewer_param = "--gcodeviewer";
{
args.reserve(3);
#ifdef __linux
static const char* gcodeviewer_param = "--gcodeviewer";
{
// If executed by an AppImage, start the AppImage, not the main process.
// 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) {
args.emplace_back(appimage_binary);
if (instance_type == NewSlicerInstanceType::GCodeViewer)
args.emplace_back(gcodeviewer_param);
}
}
#endif // __linux
#endif // __linux
std::string my_path;
if (args.empty()) {
// 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();
args.emplace_back(my_path.c_str());
}
std::string to_open;
if (path_to_open) {
to_open = into_u8(*path_to_open);
args.emplace_back(to_open.c_str());
}
args.emplace_back(nullptr);
std::string to_open;
if (!paths_to_open.empty()) {
for (const auto& file : paths_to_open) {
to_open = into_u8(file);
args.emplace_back(to_open.c_str());
}
}
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] << "\"";
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];
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];
}
#endif // Linux or Unix
#endif // Linux or Unix
#endif // Win32
}
void start_new_slicer(const wxString *path_to_open)
static void start_new_slicer_or_gcodeviewer(const NewSlicerInstanceType instance_type, const wxString* path_to_open, bool single_instance)
{
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)
{
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)

View File

@ -8,7 +8,9 @@ namespace Slic3r {
namespace GUI {
// 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.
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.