diff --git a/src/slic3r/GUI/Camera.hpp b/src/slic3r/GUI/Camera.hpp index 4b91445199..b784e7b96a 100644 --- a/src/slic3r/GUI/Camera.hpp +++ b/src/slic3r/GUI/Camera.hpp @@ -122,6 +122,13 @@ public: // returns true if the camera z axis (forward) is pointing in the negative direction of the world z axis bool is_looking_downward() const { return get_dir_forward().dot(Vec3d::UnitZ()) < 0.0; } + // forces camera right vector to be parallel to XY plane + void recover_from_free_camera() + { + if (std::abs(get_dir_right()(2)) > EPSILON) + look_at(get_position(), m_target, Vec3d::UnitZ()); + } + void look_at(const Vec3d& position, const Vec3d& target, const Vec3d& up); double max_zoom() const { return 100.0; } diff --git a/src/slic3r/GUI/GUI_ObjectList.cpp b/src/slic3r/GUI/GUI_ObjectList.cpp index 961fc2077e..e15e1ee975 100644 --- a/src/slic3r/GUI/GUI_ObjectList.cpp +++ b/src/slic3r/GUI/GUI_ObjectList.cpp @@ -115,6 +115,11 @@ ObjectList::ObjectList(wxWindow* parent) : // describe control behavior Bind(wxEVT_DATAVIEW_SELECTION_CHANGED, [this](wxDataViewEvent& event) { + // detect the current mouse position here, to pass it to list_manipulation() method + // if we detect it later, the user may have moved the mouse pointer while calculations are performed, and this would mess-up the HitTest() call performed into list_manipulation() + // see: https://github.com/prusa3d/PrusaSlicer/issues/3802 + const wxPoint mouse_pos = get_mouse_position_in_control(); + #ifndef __APPLE__ // On Windows and Linux, forces a kill focus emulation on the object manipulator fields because this event handler is called // before the kill focus event handler on the object manipulator when changing selection in the list, invalidating the object @@ -170,7 +175,7 @@ ObjectList::ObjectList(wxWindow* parent) : #endif //__WXMSW__ #ifndef __WXOSX__ - list_manipulation(); + list_manipulation(mouse_pos); #endif //__WXOSX__ }); @@ -784,23 +789,31 @@ void ObjectList::OnChar(wxKeyEvent& event) */ #endif /* __WXOSX__ */ -void ObjectList::OnContextMenu(wxDataViewEvent&) +void ObjectList::OnContextMenu(wxDataViewEvent& evt) { + // The mouse position returned by get_mouse_position_in_control() here is the one at the time the mouse button is released (mouse up event) + wxPoint mouse_pos = get_mouse_position_in_control(); + + // We check if the mouse down event was over the "Editing" column, if not, we change the mouse position so that the following call to list_simulation() does not show any context menu + // see: https://github.com/prusa3d/PrusaSlicer/issues/3802 + wxDataViewColumn* column = evt.GetDataViewColumn(); + if (column == nullptr || column->GetTitle() != _("Editing")) + mouse_pos.x = 0; + // Do not show the context menu if the user pressed the right mouse button on the 3D scene and released it on the objects list GLCanvas3D* canvas = wxGetApp().plater()->canvas3D(); bool evt_context_menu = (canvas != nullptr) ? !canvas->is_mouse_dragging() : true; if (!evt_context_menu) canvas->mouse_up_cleanup(); - list_manipulation(evt_context_menu); + list_manipulation(mouse_pos, evt_context_menu); } -void ObjectList::list_manipulation(bool evt_context_menu/* = false*/) +void ObjectList::list_manipulation(const wxPoint& mouse_pos, bool evt_context_menu/* = false*/) { wxDataViewItem item; wxDataViewColumn* col = nullptr; - const wxPoint pt = get_mouse_position_in_control(); - HitTest(pt, item, col); + HitTest(mouse_pos, item, col); if (m_extruder_editor) m_extruder_editor->Hide(); @@ -854,7 +867,7 @@ void ObjectList::list_manipulation(bool evt_context_menu/* = false*/) get_selected_item_indexes(obj_idx, vol_idx, item); if (get_mesh_errors_count(obj_idx, vol_idx) > 0 && - pt.x > 2*wxGetApp().em_unit() && pt.x < 4*wxGetApp().em_unit() ) + mouse_pos.x > 2 * wxGetApp().em_unit() && mouse_pos.x < 4 * wxGetApp().em_unit()) fix_through_netfabb(); } } diff --git a/src/slic3r/GUI/GUI_ObjectList.hpp b/src/slic3r/GUI/GUI_ObjectList.hpp index edb7d800ed..44e41a5815 100644 --- a/src/slic3r/GUI/GUI_ObjectList.hpp +++ b/src/slic3r/GUI/GUI_ObjectList.hpp @@ -381,7 +381,7 @@ private: // void OnChar(wxKeyEvent& event); #endif /* __WXOSX__ */ void OnContextMenu(wxDataViewEvent &event); - void list_manipulation(bool evt_context_menu = false); + void list_manipulation(const wxPoint& mouse_pos, bool evt_context_menu = false); void OnBeginDrag(wxDataViewEvent &event); void OnDropPossible(wxDataViewEvent &event); diff --git a/src/slic3r/GUI/Mouse3DController.cpp b/src/slic3r/GUI/Mouse3DController.cpp index 0cd39b092a..5ff817c597 100644 --- a/src/slic3r/GUI/Mouse3DController.cpp +++ b/src/slic3r/GUI/Mouse3DController.cpp @@ -388,6 +388,9 @@ void Mouse3DController::disconnected() m_params_by_device[m_device_str] = m_params_ui; m_device_str.clear(); m_connected = false; + wxGetApp().plater()->get_camera().recover_from_free_camera(); + wxGetApp().plater()->set_current_canvas_as_dirty(); + wxWakeUpIdle(); } } @@ -773,7 +776,10 @@ void Mouse3DController::disconnect_device() } m_device_str.clear(); m_connected = false; - } + wxGetApp().plater()->get_camera().recover_from_free_camera(); + wxGetApp().plater()->set_current_canvas_as_dirty(); + wxWakeUpIdle(); + } } void Mouse3DController::collect_input() diff --git a/src/slic3r/GUI/Plater.cpp b/src/slic3r/GUI/Plater.cpp index 98ef2a7122..4d5393dd94 100644 --- a/src/slic3r/GUI/Plater.cpp +++ b/src/slic3r/GUI/Plater.cpp @@ -2297,11 +2297,7 @@ void Plater::priv::update_ui_from_settings() camera.set_type(wxGetApp().app_config->get("use_perspective_camera")); if (wxGetApp().app_config->get("use_free_camera") != "1") - { - // forces camera right vector to be parallel to XY plane - if (std::abs(camera.get_dir_right()(2)) > EPSILON) - camera.look_at(camera.get_position(), camera.get_target(), Vec3d::UnitZ()); - } + camera.recover_from_free_camera(); view3D->get_canvas3d()->update_ui_from_settings(); preview->get_canvas3d()->update_ui_from_settings(); @@ -5700,12 +5696,12 @@ const Camera& Plater::get_camera() const return p->camera; } -#if ENABLE_NON_STATIC_CANVAS_MANAGER Camera& Plater::get_camera() { return p->camera; } +#if ENABLE_NON_STATIC_CANVAS_MANAGER const Bed3D& Plater::get_bed() const { return p->bed; diff --git a/src/slic3r/GUI/Plater.hpp b/src/slic3r/GUI/Plater.hpp index e05942bb88..3bacd80984 100644 --- a/src/slic3r/GUI/Plater.hpp +++ b/src/slic3r/GUI/Plater.hpp @@ -283,9 +283,9 @@ public: bool init_view_toolbar(); const Camera& get_camera() const; -#if ENABLE_NON_STATIC_CANVAS_MANAGER Camera& get_camera(); +#if ENABLE_NON_STATIC_CANVAS_MANAGER const Bed3D& get_bed() const; Bed3D& get_bed(); diff --git a/src/slic3r/GUI/RemovableDriveManager.cpp b/src/slic3r/GUI/RemovableDriveManager.cpp index 0c4c417b25..f766250498 100644 --- a/src/slic3r/GUI/RemovableDriveManager.cpp +++ b/src/slic3r/GUI/RemovableDriveManager.cpp @@ -21,6 +21,7 @@ #include #include #include +#include #endif namespace Slic3r { @@ -329,27 +330,40 @@ void RemovableDriveManager::eject_drive() auto it_drive_data = this->find_last_save_path_drive_data(); if (it_drive_data != m_current_drives.end()) { std::string correct_path(m_last_save_path); - for (size_t i = 0; i < correct_path.size(); ++i) +#ifndef __APPLE__ + for (size_t i = 0; i < correct_path.size(); ++i) if (correct_path[i]==' ') { correct_path = correct_path.insert(i,1,'\\'); ++ i; } +#endif //std::cout<<"Ejecting "<<(*it).name<<" from "<< correct_path<<"\n"; // there is no usable command in c++ so terminal command is used instead // but neither triggers "succesful safe removal messege" - std::string command = -#if __APPLE__ - //this->eject_device(m_last_save_path); - "diskutil unmount "; + BOOST_LOG_TRIVIAL(info) << "Ejecting started"; + boost::process::ipstream istd_err; + boost::process::child child( +#if __APPLE__ + boost::process::search_path("diskutil"), "eject", correct_path.c_str(), (boost::process::std_out & boost::process::std_err) > istd_err); + //Another option how to eject at mac. Currently not working. + //used insted of system() command; + //this->eject_device(correct_path); #else - "umount "; + boost::process::search_path("umount"), correct_path.c_str(), (boost::process::std_out & boost::process::std_err) > istd_err); #endif - command += correct_path; - int err = system(command.c_str()); - if (err) { - BOOST_LOG_TRIVIAL(error) << "Ejecting " << m_last_save_path << " failed"; - return; + std::string line; + while (child.running() && std::getline(istd_err, line)) { + BOOST_LOG_TRIVIAL(trace) << line; } + // wait for command to finnish (blocks ui thread) + child.wait(); + int err = child.exit_code(); + if(err) + { + BOOST_LOG_TRIVIAL(error) << "Ejecting failed"; + return; + } + BOOST_LOG_TRIVIAL(info) << "Ejecting finished"; assert(m_callback_evt_handler); if (m_callback_evt_handler) diff --git a/src/slic3r/GUI/RemovableDriveManagerMM.mm b/src/slic3r/GUI/RemovableDriveManagerMM.mm index c2f55bb790..3e4b32f295 100644 --- a/src/slic3r/GUI/RemovableDriveManagerMM.mm +++ b/src/slic3r/GUI/RemovableDriveManagerMM.mm @@ -4,10 +4,22 @@ #import #import +static void eject_callback(DADiskRef disk, DADissenterRef dissenter, void *context) +{ + NSLog(@"eject successfull"); +} + +static void unmount_callback(DADiskRef disk, DADissenterRef dissenter, void *context) +{ + //if (dissenter) { + //? + //} else { + DADiskEject(disk, kDADiskEjectOptionDefault, eject_callback, context); + //} +} + @implementation RemovableDriveManagerMM - - -(instancetype) init { self = [super init]; @@ -59,9 +71,17 @@ CFTypeRef mediaEjectableKey = CFDictionaryGetValue(descDict,kDADiskDescriptionMediaEjectableKey); BOOL ejectable = [mediaEjectableKey boolValue]; CFTypeRef deviceProtocolName = CFDictionaryGetValue(descDict,kDADiskDescriptionDeviceProtocolKey); + CFTypeRef deviceModelKey = CFDictionaryGetValue(descDict, kDADiskDescriptionDeviceModelKey); + //debug logging + /* + if (deviceProtocolName) + NSLog(@"%@",(CFStringRef)deviceProtocolName); + if (deviceModelKey) + NSLog(@"-%@",(CFStringRef)deviceModelKey); + */ if (mediaEjectableKey != nullptr) { - BOOL op = ejectable && (CFEqual(deviceProtocolName, CFSTR("USB")) || CFEqual(deviceModelKey, CFSTR("SD Card Reader"))); + BOOL op = ejectable && (CFEqual(deviceProtocolName, CFSTR("USB")) || CFEqual(deviceModelKey, CFSTR("SD Card Reader")) || CFEqual(deviceProtocolName, CFSTR("Secure Digital"))); //!CFEqual(deviceModelKey, CFSTR("Disk Image")); if (op) [result addObject:volURL.path]; @@ -86,7 +106,8 @@ if (err == 0) disk = DADiskCreateFromVolumePath(nullptr,session,(CFURLRef)url); if( err == 0) - DADiskUnmount(disk, kDADiskUnmountOptionDefault, nullptr, nullptr); + //DADiskUnmount(disk, kDADiskUnmountOptionDefault, nullptr, nullptr); + DADiskUnmount(disk, kDADiskUnmountOptionWhole | kDADiskUnmountOptionForce, unmount_callback, nullptr); if (disk != nullptr) CFRelease(disk); if (session != nullptr)