diff --git a/resources/images/notification_eject_sd.svg b/resources/images/notification_eject_sd.svg new file mode 100644 index 0000000000..692c50d03b --- /dev/null +++ b/resources/images/notification_eject_sd.svg @@ -0,0 +1 @@ +notification_eject_sd \ No newline at end of file diff --git a/resources/images/notification_eject_sd_hover.svg b/resources/images/notification_eject_sd_hover.svg new file mode 100644 index 0000000000..d41e03f097 --- /dev/null +++ b/resources/images/notification_eject_sd_hover.svg @@ -0,0 +1 @@ +notification_eject_sd_hover \ No newline at end of file diff --git a/src/slic3r/CMakeLists.txt b/src/slic3r/CMakeLists.txt index 07be68a79c..1408ccc849 100644 --- a/src/slic3r/CMakeLists.txt +++ b/src/slic3r/CMakeLists.txt @@ -253,8 +253,8 @@ set(SLIC3R_GUI_SOURCES GUI/wxExtensions.hpp GUI/WipeTowerDialog.cpp GUI/WipeTowerDialog.hpp - #GUI/RemovableDriveManager.cpp - #GUI/RemovableDriveManager.hpp + GUI/RemovableDriveManager.cpp + GUI/RemovableDriveManager.hpp GUI/SendSystemInfoDialog.cpp GUI/SendSystemInfoDialog.hpp GUI/ImGuiWrapper.hpp @@ -387,8 +387,8 @@ if (APPLE) list(APPEND SLIC3R_GUI_SOURCES Utils/RetinaHelperImpl.mm Utils/MacDarkMode.mm - #GUI/RemovableDriveManagerMM.mm - #GUI/RemovableDriveManagerMM.h + GUI/RemovableDriveManagerMM.mm + GUI/RemovableDriveManagerMM.h GUI/Mouse3DHandlerMac.mm #GUI/InstanceCheckMac.mm #GUI/InstanceCheckMac.h diff --git a/src/slic3r/GUI/GUI_App.cpp b/src/slic3r/GUI/GUI_App.cpp index 61fdbe29fa..0b19e9bdb8 100644 --- a/src/slic3r/GUI/GUI_App.cpp +++ b/src/slic3r/GUI/GUI_App.cpp @@ -65,7 +65,7 @@ #include "SysInfoDialog.hpp" #include "UpdateDialogs.hpp" #include "Mouse3DController.hpp" -//#include "RemovableDriveManager.hpp" +#include "RemovableDriveManager.hpp" #include "InstanceCheck.hpp" #include "NotificationManager.hpp" #include "UnsavedChangesDialog.hpp" @@ -1119,7 +1119,7 @@ GUI_App::GUI_App() , m_em_unit(10) , m_imgui(new ImGuiWrapper()) , hms_query(new HMSQuery()) - //, m_removable_drive_manager(std::make_unique()) + , m_removable_drive_manager(std::make_unique()) //, m_other_instance_message_handler(std::make_unique()) { //app config initializes early becasuse it is used in instance checking in BambuStudio.cpp diff --git a/src/slic3r/GUI/GUI_App.hpp b/src/slic3r/GUI/GUI_App.hpp index 2cacc0cc26..8f189f0952 100644 --- a/src/slic3r/GUI/GUI_App.hpp +++ b/src/slic3r/GUI/GUI_App.hpp @@ -49,7 +49,7 @@ class NetworkAgent; namespace GUI{ -//class RemovableDriveManager; +class RemovableDriveManager; class OtherInstanceMessageHandler; class MainFrame; class Sidebar; @@ -244,7 +244,7 @@ private: const wxLanguageInfo *m_language_info_best = nullptr; OpenGLManager m_opengl_mgr; - //std::unique_ptr m_removable_drive_manager; + std::unique_ptr m_removable_drive_manager; std::unique_ptr m_imgui; //std::unique_ptr m_other_instance_message_handler; @@ -479,7 +479,7 @@ public: std::vector tabs_list; std::vector model_tabs_list; - //RemovableDriveManager* removable_drive_manager() { return m_removable_drive_manager.get(); } + RemovableDriveManager* removable_drive_manager() { return m_removable_drive_manager.get(); } //OtherInstanceMessageHandler* other_instance_message_handler() { return m_other_instance_message_handler.get(); } //wxSingleInstanceChecker* single_instance_checker() {return m_single_instance_checker.get();} diff --git a/src/slic3r/GUI/ImGuiWrapper.cpp b/src/slic3r/GUI/ImGuiWrapper.cpp index 7c497219ef..9d7ec10142 100644 --- a/src/slic3r/GUI/ImGuiWrapper.cpp +++ b/src/slic3r/GUI/ImGuiWrapper.cpp @@ -71,8 +71,8 @@ static const std::map font_icons_large = { {ImGui::CloseNotifButton , "notification_close" }, {ImGui::CloseNotifHoverButton , "notification_close_hover" }, //BBS removed - //{ImGui::EjectButton , "notification_eject_sd" }, - //{ImGui::EjectHoverButton , "notification_eject_sd_hover" }, + {ImGui::EjectButton , "notification_eject_sd" }, + {ImGui::EjectHoverButton , "notification_eject_sd_hover" }, //{ImGui::WarningMarker , "notification_warning" }, //{ImGui::ErrorMarker , "notification_error" }, {ImGui::CancelButton , "notification_cancel" }, diff --git a/src/slic3r/GUI/NotificationManager.cpp b/src/slic3r/GUI/NotificationManager.cpp index 5ee129c3b9..d0532cca09 100644 --- a/src/slic3r/GUI/NotificationManager.cpp +++ b/src/slic3r/GUI/NotificationManager.cpp @@ -34,7 +34,7 @@ static constexpr int FADING_OUT_TIMEOUT = 100; namespace Slic3r { namespace GUI { -//wxDEFINE_EVENT(EVT_EJECT_DRIVE_NOTIFICAION_CLICKED, EjectDriveNotificationClickedEvent); +wxDEFINE_EVENT(EVT_EJECT_DRIVE_NOTIFICAION_CLICKED, EjectDriveNotificationClickedEvent); wxDEFINE_EVENT(EVT_EXPORT_GCODE_NOTIFICAION_CLICKED, ExportGcodeNotificationClickedEvent); wxDEFINE_EVENT(EVT_PRESET_UPDATE_AVAILABLE_CLICKED, PresetUpdateAvailableClickedEvent); @@ -801,11 +801,11 @@ void NotificationManager::ExportFinishedNotification::render_text(ImGuiWrapper& void NotificationManager::ExportFinishedNotification::render_close_button(ImGuiWrapper& imgui, const float win_size_x, const float win_size_y, const float win_pos_x, const float win_pos_y) { PopNotification::render_close_button(imgui, win_size_x, win_size_y, win_pos_x, win_pos_y); - //if(m_to_removable && ! m_eject_pending) - // render_eject_button(imgui, win_size_x, win_size_y, win_pos_x, win_pos_y); + if (m_to_removable && !m_eject_pending) + render_eject_button(imgui, win_size_x, win_size_y, win_pos_x, win_pos_y); } -/*void NotificationManager::ExportFinishedNotification::render_eject_button(ImGuiWrapper& imgui, const float win_size_x, const float win_size_y, const float win_pos_x, const float win_pos_y) +void NotificationManager::ExportFinishedNotification::render_eject_button(ImGuiWrapper& imgui, const float win_size_x, const float win_size_y, const float win_pos_x, const float win_pos_y) { ImVec2 win_size(win_size_x, win_size_y); ImVec2 win_pos(win_pos_x, win_pos_y); @@ -818,23 +818,25 @@ void NotificationManager::ExportFinishedNotification::render_close_button(ImGuiW std::string button_text; button_text = ImGui::EjectButton; - if (ImGui::IsMouseHoveringRect(ImVec2(win_pos.x - m_line_height * 5.f, win_pos.y), + if (ImGui::IsMouseHoveringRect(ImVec2(win_pos.x - m_line_height * 5.f, win_pos.y), ImVec2(win_pos.x - m_line_height * 2.5f, win_pos.y + win_size.y), true)) { button_text = ImGui::EjectHoverButton; - // tooltip + //tooltip + long time_now = wxGetLocalTime(); if (m_hover_time > 0 && m_hover_time < time_now) { ImGui::PushStyleColor(ImGuiCol_PopupBg, ImGuiWrapper::COL_WINDOW_BACKGROUND); - ImGui::BeginTooltip(); - imgui.text(_u8L("Eject drive") + " " + GUI::shortkey_ctrl_prefix() + "T"); - ImGui::EndTooltip(); + //ImGui::BeginTooltip(); + //imgui.text(_u8L("Eject drive") + " " + GUI::shortkey_ctrl_prefix() + "T"); + //ImGui::EndTooltip(); ImGui::PopStyleColor(); } if (m_hover_time == 0) m_hover_time = time_now; - } else + } + else m_hover_time = 0; ImVec2 button_pic_size = ImGui::CalcTextSize(button_text.c_str()); @@ -850,7 +852,7 @@ void NotificationManager::ExportFinishedNotification::render_close_button(ImGuiW } //invisible large button - ImGui::SetCursorPosX(win_size.x - m_line_height * 4.625f); + ImGui::SetCursorPosX(win_size.x - m_line_height * 4.625f); ImGui::SetCursorPosY(0); if (imgui.button(" ", m_line_height * 2.f, win_size.y)) { @@ -860,7 +862,8 @@ void NotificationManager::ExportFinishedNotification::render_close_button(ImGuiW on_eject_click(); } ImGui::PopStyleColor(5); -}*/ +} + bool NotificationManager::ExportFinishedNotification::on_text_click() { open_folder(m_export_dir_path); diff --git a/src/slic3r/GUI/NotificationManager.hpp b/src/slic3r/GUI/NotificationManager.hpp index d758dbe061..a731c551a9 100644 --- a/src/slic3r/GUI/NotificationManager.hpp +++ b/src/slic3r/GUI/NotificationManager.hpp @@ -21,8 +21,8 @@ namespace Slic3r { namespace GUI { -//using EjectDriveNotificationClickedEvent = SimpleEvent; -//wxDECLARE_EVENT(EVT_EJECT_DRIVE_NOTIFICAION_CLICKED, EjectDriveNotificationClickedEvent); +using EjectDriveNotificationClickedEvent = SimpleEvent; +wxDECLARE_EVENT(EVT_EJECT_DRIVE_NOTIFICAION_CLICKED, EjectDriveNotificationClickedEvent); using ExportGcodeNotificationClickedEvent = SimpleEvent; wxDECLARE_EVENT(EVT_EXPORT_GCODE_NOTIFICAION_CLICKED, ExportGcodeNotificationClickedEvent); using PresetUpdateAvailableClickedEvent = SimpleEvent; @@ -690,9 +690,9 @@ private: void render_close_button(ImGuiWrapper& imgui, const float win_size_x, const float win_size_y, const float win_pos_x, const float win_pos_y) override; - /*void render_eject_button(ImGuiWrapper& imgui, + void render_eject_button(ImGuiWrapper& imgui, const float win_size_x, const float win_size_y, - const float win_pos_x, const float win_pos_y);*/ + const float win_pos_x, const float win_pos_y); void render_minimize_button(ImGuiWrapper& imgui, const float win_pos_x, const float win_pos_y) override { m_minimize_b_visible = false; } bool on_text_click() override; diff --git a/src/slic3r/GUI/Plater.cpp b/src/slic3r/GUI/Plater.cpp index fe0938ad84..f7b7a6b349 100644 --- a/src/slic3r/GUI/Plater.cpp +++ b/src/slic3r/GUI/Plater.cpp @@ -91,7 +91,7 @@ #include "../Utils/UndoRedo.hpp" #include "../Utils/PresetUpdater.hpp" #include "../Utils/Process.hpp" -//#include "RemovableDriveManager.hpp" +#include "RemovableDriveManager.hpp" #include "InstanceCheck.hpp" #include "NotificationManager.hpp" #include "PresetComboBoxes.hpp" @@ -2240,12 +2240,11 @@ Plater::priv::priv(Plater *q, MainFrame *main_frame) //notification_manager = new NotificationManager(this->q); if (wxGetApp().is_editor()) { - //this->q->Bind(EVT_EJECT_DRIVE_NOTIFICAION_CLICKED, [this](EjectDriveNotificationClickedEvent&) { this->q->eject_drive(); }); + this->q->Bind(EVT_EJECT_DRIVE_NOTIFICAION_CLICKED, [this](EjectDriveNotificationClickedEvent&) { this->q->eject_drive(); }); this->q->Bind(EVT_EXPORT_GCODE_NOTIFICAION_CLICKED, [this](ExportGcodeNotificationClickedEvent&) { this->q->export_gcode(true); }); this->q->Bind(EVT_PRESET_UPDATE_AVAILABLE_CLICKED, [](PresetUpdateAvailableClickedEvent&) { wxGetApp().get_preset_updater()->on_update_notification_confirm(); }); /* BBS do not handle removeable driver event */ - /* this->q->Bind(EVT_REMOVABLE_DRIVE_EJECTED, [this](RemovableDriveEjectEvent &evt) { if (evt.data.second) { // BBS @@ -2268,14 +2267,13 @@ Plater::priv::priv(Plater *q, MainFrame *main_frame) // Close notification ExportingFinished but only if last export was to removable notification_manager->device_ejected(); }); - */ // Start the background thread and register this window as a target for update events. - //wxGetApp().removable_drive_manager()->init(this->q); -//#ifdef _WIN32 - // Trigger enumeration of removable media on Win32 notification. - //this->q->Bind(EVT_VOLUME_ATTACHED, [this](VolumeAttachedEvent &evt) { wxGetApp().removable_drive_manager()->volumes_changed(); }); - //this->q->Bind(EVT_VOLUME_DETACHED, [this](VolumeDetachedEvent &evt) { wxGetApp().removable_drive_manager()->volumes_changed(); }); -//#endif /* _WIN32 */ + wxGetApp().removable_drive_manager()->init(this->q); +#ifdef _WIN32 + //Trigger enumeration of removable media on Win32 notification. + this->q->Bind(EVT_VOLUME_ATTACHED, [this](VolumeAttachedEvent &evt) { wxGetApp().removable_drive_manager()->volumes_changed(); }); + this->q->Bind(EVT_VOLUME_DETACHED, [this](VolumeDetachedEvent &evt) { wxGetApp().removable_drive_manager()->volumes_changed(); }); +#endif /* _WIN32 */ } // Initialize the Undo / Redo stack with a first snapshot. @@ -5382,16 +5380,16 @@ void Plater::priv::on_process_completed(SlicingProcessCompletedEvent &evt) notification_manager->close_notification_of_type(NotificationType::ExportOngoing); } // If writing to removable drive was scheduled, show notification with eject button - /*if (exporting_status == ExportingStatus::EXPORTING_TO_REMOVABLE && !has_error) { + if (exporting_status == ExportingStatus::EXPORTING_TO_REMOVABLE && !has_error) { //show_action_buttons(ready_to_slice); this->main_frame->update_slice_print_status(MainFrame::eEventSliceUpdate, ready_to_slice, true); notification_manager->push_exporting_finished_notification(last_output_path, last_output_dir_path, // Don't offer the "Eject" button on ChromeOS, the Linux side has no control over it. platform_flavor() != PlatformFlavor::LinuxOnChromium); - //wxGetApp().removable_drive_manager()->set_exporting_finished(true); - }else */ - //if (exporting_status == ExportingStatus::EXPORTING_TO_LOCAL && !has_error) - // notification_manager->push_exporting_finished_notification(last_output_path, last_output_dir_path, false); + wxGetApp().removable_drive_manager()->set_exporting_finished(true); + }else + if (exporting_status == ExportingStatus::EXPORTING_TO_LOCAL && !has_error) + notification_manager->push_exporting_finished_notification(last_output_path, last_output_dir_path, false); } exporting_status = ExportingStatus::NOT_EXPORTING; @@ -8172,16 +8170,16 @@ void Plater::export_gcode(bool prefer_removable) } default_output_file = fs::path(Slic3r::fold_utf8_to_ascii(default_output_file.string())); AppConfig &appconfig = *wxGetApp().app_config; - //RemovableDriveManager &removable_drive_manager = *wxGetApp().removable_drive_manager(); + RemovableDriveManager &removable_drive_manager = *wxGetApp().removable_drive_manager(); // Get a last save path, either to removable media or to an internal media. std::string start_dir = appconfig.get_last_output_dir(default_output_file.parent_path().string(), prefer_removable); - /*if (prefer_removable) { + if (prefer_removable) { // Returns a path to a removable media if it exists, prefering start_dir. Update the internal removable drives database. start_dir = removable_drive_manager.get_removable_drive_path(start_dir); if (start_dir.empty()) // Direct user to the last internal media. start_dir = appconfig.get_last_output_dir(default_output_file.parent_path().string(), false); - }*/ + } fs::path output_path; { @@ -8209,8 +8207,8 @@ void Plater::export_gcode(bool prefer_removable) } if (! output_path.empty()) { - //bool path_on_removable_media = removable_drive_manager.set_and_verify_last_save_path(output_path.string()); - bool path_on_removable_media = false; + bool path_on_removable_media = removable_drive_manager.set_and_verify_last_save_path(output_path.string()); + //bool path_on_removable_media = false; p->notification_manager->new_export_began(path_on_removable_media); p->exporting_status = path_on_removable_media ? ExportingStatus::EXPORTING_TO_REMOVABLE : ExportingStatus::EXPORTING_TO_LOCAL; p->last_output_path = output_path.string(); @@ -8279,13 +8277,20 @@ void Plater::export_gcode_3mf() p->notification_manager->new_export_began(path_on_removable_media); p->exporting_status = path_on_removable_media ? ExportingStatus::EXPORTING_TO_REMOVABLE : ExportingStatus::EXPORTING_TO_LOCAL; //BBS do not save last output path - //p->last_output_path = output_path.string(); + p->last_output_path = output_path.string(); p->last_output_dir_path = output_path.parent_path().string(); int curr_plate_idx = get_partplate_list().get_curr_plate_index(); export_3mf(output_path, SaveStrategy::Silence | SaveStrategy::SplitModel | SaveStrategy::WithGcode | SaveStrategy::SkipModel, curr_plate_idx); // BBS: silence - // update lost output dir + + RemovableDriveManager& removable_drive_manager = *wxGetApp().removable_drive_manager(); + + + bool on_removable = removable_drive_manager.is_path_on_removable_drive(p->last_output_dir_path); + + + // update last output dir appconfig.update_last_output_dir(output_path.parent_path().string(), false); - p->notification_manager->push_exporting_finished_notification(output_path.string(), p->last_output_dir_path, false); + p->notification_manager->push_exporting_finished_notification(output_path.string(), p->last_output_dir_path, on_removable); } } @@ -8925,11 +8930,12 @@ void Plater::print_job_finished(wxCommandEvent &evt) } // Called when the Eject button is pressed. -/*void Plater::eject_drive() +void Plater::eject_drive() { - wxBusyCursor wait; - wxGetApp().removable_drive_manager()->eject_drive(); -}*/ + wxBusyCursor wait; + wxGetApp().removable_drive_manager()->set_and_verify_last_save_path(p->last_output_dir_path); + wxGetApp().removable_drive_manager()->eject_drive(); +} void Plater::take_snapshot(const std::string &snapshot_name) { p->take_snapshot(snapshot_name); } //void Plater::take_snapshot(const wxString &snapshot_name) { p->take_snapshot(snapshot_name); } diff --git a/src/slic3r/GUI/Plater.hpp b/src/slic3r/GUI/Plater.hpp index 2d24bae3a9..5460ffcdd1 100644 --- a/src/slic3r/GUI/Plater.hpp +++ b/src/slic3r/GUI/Plater.hpp @@ -332,7 +332,7 @@ public: int export_config_3mf(int plate_idx = -1, Export3mfProgressFn proFn = nullptr); //BBS jump to nonitor after print job finished void print_job_finished(wxCommandEvent &evt); - //void eject_drive(); + void eject_drive(); void take_snapshot(const std::string &snapshot_name); //void take_snapshot(const wxString &snapshot_name); diff --git a/src/slic3r/GUI/RemovableDriveManager.cpp b/src/slic3r/GUI/RemovableDriveManager.cpp index 74e3bd371e..10c692a69b 100644 --- a/src/slic3r/GUI/RemovableDriveManager.cpp +++ b/src/slic3r/GUI/RemovableDriveManager.cpp @@ -442,7 +442,14 @@ bool RemovableDriveManager::set_and_verify_last_save_path(const std::string &pat #ifndef REMOVABLE_DRIVE_MANAGER_OS_CALLBACKS this->update(); #endif // REMOVABLE_DRIVE_MANAGER_OS_CALLBACKS + +#ifdef __APPLE__ + m_last_save_path = path; +#else m_last_save_path = this->get_removable_drive_from_path(path); +#endif + + m_exporting_finished = false; return ! m_last_save_path.empty(); } diff --git a/src/slic3r/GUI/RemovableDriveManager.hpp b/src/slic3r/GUI/RemovableDriveManager.hpp index 29363647c8..ea8b4e83a7 100644 --- a/src/slic3r/GUI/RemovableDriveManager.hpp +++ b/src/slic3r/GUI/RemovableDriveManager.hpp @@ -49,7 +49,7 @@ public: RemovableDriveManager() = default; RemovableDriveManager(RemovableDriveManager const&) = delete; void operator=(RemovableDriveManager const&) = delete; - ~RemovableDriveManager() { assert(! m_initialized); } + ~RemovableDriveManager() { /*assert(! m_initialized);*/ } // Start the background thread and register this window as a target for update events. // Register for OSX notifications.