diff --git a/src/libslic3r/SupportMaterial.cpp b/src/libslic3r/SupportMaterial.cpp index 2bcf99c57..d1234bc1a 100644 --- a/src/libslic3r/SupportMaterial.cpp +++ b/src/libslic3r/SupportMaterial.cpp @@ -1599,7 +1599,8 @@ static inline std::tuple<Polygons, Polygons, Polygons, float> detect_overhangs( static inline std::pair<PrintObjectSupportMaterial::MyLayer*, PrintObjectSupportMaterial::MyLayer*> new_contact_layer( const PrintConfig &print_config, const PrintObjectConfig &object_config, - const SlicingParameters &slicing_params, + const SlicingParameters &slicing_params, + const coordf_t support_layer_height_min, const Layer &layer, std::deque<PrintObjectSupportMaterial::MyLayer> &layer_storage, tbb::spin_mutex &layer_storage_mutex) @@ -1629,7 +1630,8 @@ static inline std::pair<PrintObjectSupportMaterial::MyLayer*, PrintObjectSupport // Don't want to print a layer below the first layer height as it may not stick well. //FIXME there may be a need for a single layer support, then one may decide to print it either as a bottom contact or a top contact // and it may actually make sense to do it with a thinner layer than the first layer height. - if (print_z < slicing_params.first_print_layer_height - EPSILON) { + const coordf_t min_print_z = slicing_params.has_raft() ? slicing_params.raft_interface_top_z + support_layer_height_min + EPSILON : slicing_params.first_print_layer_height - EPSILON; + if (print_z < min_print_z) { // This contact layer is below the first layer height, therefore not printable. Don't support this surface. return std::pair<PrintObjectSupportMaterial::MyLayer*, PrintObjectSupportMaterial::MyLayer*>(nullptr, nullptr); } else if (print_z < slicing_params.first_print_layer_height + EPSILON) { @@ -1650,7 +1652,7 @@ static inline std::pair<PrintObjectSupportMaterial::MyLayer*, PrintObjectSupport bridging_height += region->region().bridging_height_avg(print_config); bridging_height /= coordf_t(layer.regions().size()); coordf_t bridging_print_z = layer.print_z - bridging_height - slicing_params.gap_support_object; - if (bridging_print_z >= slicing_params.first_print_layer_height - EPSILON) { + if (bridging_print_z >= min_print_z) { // Not below the first layer height means this layer is printable. if (print_z < slicing_params.first_print_layer_height + EPSILON) { // Align the layer with the 1st layer height. @@ -1664,8 +1666,7 @@ static inline std::pair<PrintObjectSupportMaterial::MyLayer*, PrintObjectSupport if (bridging_print_z == slicing_params.first_print_layer_height) { bridging_layer->bottom_z = 0; bridging_layer->height = slicing_params.first_print_layer_height; - } - else { + } else { // Don't know the height yet. bridging_layer->bottom_z = bridging_print_z; bridging_layer->height = 0; @@ -1917,7 +1918,7 @@ PrintObjectSupportMaterial::MyLayersPtr PrintObjectSupportMaterial::top_contact_ // Now apply the contact areas to the layer where they need to be made. if (! contact_polygons.empty()) { - auto [new_layer, bridging_layer] = new_contact_layer(*m_print_config, *m_object_config, m_slicing_params, layer, layer_storage, layer_storage_mutex); + auto [new_layer, bridging_layer] = new_contact_layer(*m_print_config, *m_object_config, m_slicing_params, m_support_params.support_layer_height_min, layer, layer_storage, layer_storage_mutex); if (new_layer) { fill_contact_layer(*new_layer, layer_id, m_slicing_params, *m_object_config, slices_margin, overhang_polygons, contact_polygons, enforcer_polygons, lower_layer_polygons, diff --git a/src/slic3r/GUI/DoubleSlider.cpp b/src/slic3r/GUI/DoubleSlider.cpp index f83078261..77679a1ad 100644 --- a/src/slic3r/GUI/DoubleSlider.cpp +++ b/src/slic3r/GUI/DoubleSlider.cpp @@ -1819,7 +1819,8 @@ void Control::OnChar(wxKeyEvent& event) void Control::OnRightDown(wxMouseEvent& event) { - if (HasCapture()) return; + if (HasCapture() || m_is_left_down) + return; this->CaptureMouse(); const wxPoint pos = event.GetLogicalPosition(wxClientDC(this)); @@ -2097,7 +2098,7 @@ void Control::auto_color_change() void Control::OnRightUp(wxMouseEvent& event) { - if (!HasCapture()) + if (!HasCapture() || m_is_left_down) return; this->ReleaseMouse(); m_is_right_down = m_is_one_layer = false; diff --git a/src/slic3r/GUI/Notebook.hpp b/src/slic3r/GUI/Notebook.hpp index 56ae5b285..ff5020b9c 100644 --- a/src/slic3r/GUI/Notebook.hpp +++ b/src/slic3r/GUI/Notebook.hpp @@ -84,6 +84,9 @@ public: if (int page_idx = evt.GetId(); page_idx >= 0) SetSelection(page_idx); }); + + this->Bind(wxEVT_NAVIGATION_KEY, &Notebook::OnNavigationKey, this); + return true; } @@ -242,6 +245,89 @@ public: GetBtnsListCtrl()->Rescale(); } + void Notebook::OnNavigationKey(wxNavigationKeyEvent& event) + { + if (event.IsWindowChange()) { + // change pages + AdvanceSelection(event.GetDirection()); + } + else { + // we get this event in 3 cases + // + // a) one of our pages might have generated it because the user TABbed + // out from it in which case we should propagate the event upwards and + // our parent will take care of setting the focus to prev/next sibling + // + // or + // + // b) the parent panel wants to give the focus to us so that we + // forward it to our selected page. We can't deal with this in + // OnSetFocus() because we don't know which direction the focus came + // from in this case and so can't choose between setting the focus to + // first or last panel child + // + // or + // + // c) we ourselves (see MSWTranslateMessage) generated the event + // + wxWindow* const parent = GetParent(); + + // the wxObject* casts are required to avoid MinGW GCC 2.95.3 ICE + const bool isFromParent = event.GetEventObject() == (wxObject*)parent; + const bool isFromSelf = event.GetEventObject() == (wxObject*)this; + const bool isForward = event.GetDirection(); + + if (isFromSelf && !isForward) + { + // focus is currently on notebook tab and should leave + // it backwards (Shift-TAB) + event.SetCurrentFocus(this); + parent->HandleWindowEvent(event); + } + else if (isFromParent || isFromSelf) + { + // no, it doesn't come from child, case (b) or (c): forward to a + // page but only if entering notebook page (i.e. direction is + // backwards (Shift-TAB) comething from out-of-notebook, or + // direction is forward (TAB) from ourselves), + if (m_selection != wxNOT_FOUND && + (!event.GetDirection() || isFromSelf)) + { + // so that the page knows that the event comes from it's parent + // and is being propagated downwards + event.SetEventObject(this); + + wxWindow* page = m_pages[m_selection]; + if (!page->HandleWindowEvent(event)) + { + page->SetFocus(); + } + //else: page manages focus inside it itself + } + else // otherwise set the focus to the notebook itself + { + SetFocus(); + } + } + else + { + // it comes from our child, case (a), pass to the parent, but only + // if the direction is forwards. Otherwise set the focus to the + // notebook itself. The notebook is always the 'first' control of a + // page. + if (!isForward) + { + SetFocus(); + } + else if (parent) + { + event.SetCurrentFocus(this); + parent->HandleWindowEvent(event); + } + } + } + } + protected: virtual void UpdateSelectedPage(size_t WXUNUSED(newsel)) override { diff --git a/src/slic3r/GUI/NotificationManager.cpp b/src/slic3r/GUI/NotificationManager.cpp index bf43b7645..1b08e6cd2 100644 --- a/src/slic3r/GUI/NotificationManager.cpp +++ b/src/slic3r/GUI/NotificationManager.cpp @@ -593,7 +593,7 @@ bool NotificationManager::PopNotification::update_state(bool paused, const int64 m_state = EState::Unknown; init(); // Timers when not fading - } else if (m_state != EState::NotFading && m_state != EState::FadingOut && get_duration() != 0 && !paused) { + } else if (m_state != EState::NotFading && m_state != EState::FadingOut && m_state != EState::ClosePending && m_state != EState::Finished && get_duration() != 0 && !paused) { int64_t up_time = now - m_notification_start; if (up_time >= get_duration() * 1000) { m_state = EState::FadingOut; @@ -633,6 +633,10 @@ bool NotificationManager::PopNotification::update_state(bool paused, const int64 //---------------ExportFinishedNotification----------- void NotificationManager::ExportFinishedNotification::count_spaces() { + if (m_eject_pending) + { + return PopNotification::count_spaces(); + } //determine line width m_line_height = ImGui::CalcTextSize("A").y; @@ -650,7 +654,10 @@ void NotificationManager::ExportFinishedNotification::count_spaces() void NotificationManager::ExportFinishedNotification::render_text(ImGuiWrapper& imgui, const float win_size_x, const float win_size_y, const float win_pos_x, const float win_pos_y) { - + if (m_eject_pending) + { + return PopNotification::render_text(imgui, win_size_x, win_size_y, win_pos_x, win_pos_y); + } float x_offset = m_left_indentation; std::string fulltext = m_text1 + m_hypertext; //+ m_text2; // Lines are always at least two and m_multiline is always true for ExportFinishedNotification. @@ -669,7 +676,7 @@ void NotificationManager::ExportFinishedNotification::render_text(ImGuiWrapper& ImGui::SetCursorPosY(starting_y + i * shift_y); imgui.text(line.c_str()); //hyperlink text - if ( i == 0 ) { + if ( i == 0 && !m_eject_pending) { render_hypertext(imgui, x_offset + ImGui::CalcTextSize(line.c_str()).x + ImGui::CalcTextSize(" ").x, starting_y, _u8L("Open Folder.")); } } @@ -680,7 +687,7 @@ 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) + if(m_to_removable && ! m_eject_pending) render_eject_button(imgui, win_size_x, win_size_y, win_pos_x, win_pos_y); } @@ -725,7 +732,7 @@ void NotificationManager::ExportFinishedNotification::render_eject_button(ImGuiW assert(m_evt_handler != nullptr); if (m_evt_handler != nullptr) wxPostEvent(m_evt_handler, EjectDriveNotificationClickedEvent(EVT_EJECT_DRIVE_NOTIFICAION_CLICKED)); - close(); + on_eject_click(); } //invisible large button @@ -736,7 +743,7 @@ void NotificationManager::ExportFinishedNotification::render_eject_button(ImGuiW assert(m_evt_handler != nullptr); if (m_evt_handler != nullptr) wxPostEvent(m_evt_handler, EjectDriveNotificationClickedEvent(EVT_EJECT_DRIVE_NOTIFICAION_CLICKED)); - close(); + on_eject_click(); } ImGui::PopStyleColor(5); } @@ -745,6 +752,14 @@ bool NotificationManager::ExportFinishedNotification::on_text_click() open_folder(m_export_dir_path); return false; } +void NotificationManager::ExportFinishedNotification::on_eject_click() +{ + NotificationData data{ get_data().type, get_data().level , 0, _utf8("Ejecting.") }; + m_eject_pending = true; + m_multiline = false; + update(data); +} + //------ProgressBar---------------- void NotificationManager::ProgressBarNotification::init() { @@ -1071,7 +1086,7 @@ void NotificationManager::UpdatedItemsInfoNotification::render_left_sign(ImGuiWr imgui.text(text.c_str()); } -//------SlicingProgressNotificastion +//------SlicingProgressNotification void NotificationManager::SlicingProgressNotification::init() { if (m_sp_state == SlicingProgressState::SP_PROGRESS) { @@ -1084,46 +1099,53 @@ void NotificationManager::SlicingProgressNotification::init() } } -void NotificationManager::SlicingProgressNotification::set_progress_state(float percent) +bool NotificationManager::SlicingProgressNotification::set_progress_state(float percent) { if (percent < 0.f) - set_progress_state(SlicingProgressState::SP_CANCELLED); + return true;//set_progress_state(SlicingProgressState::SP_CANCELLED); else if (percent >= 1.f) - set_progress_state(SlicingProgressState::SP_COMPLETED); + return set_progress_state(SlicingProgressState::SP_COMPLETED); else - set_progress_state(SlicingProgressState::SP_PROGRESS, percent); + return set_progress_state(SlicingProgressState::SP_PROGRESS, percent); } -void NotificationManager::SlicingProgressNotification::set_progress_state(NotificationManager::SlicingProgressNotification::SlicingProgressState state, float percent/* = 0.f*/) +bool NotificationManager::SlicingProgressNotification::set_progress_state(NotificationManager::SlicingProgressNotification::SlicingProgressState state, float percent/* = 0.f*/) { switch (state) { case Slic3r::GUI::NotificationManager::SlicingProgressNotification::SlicingProgressState::SP_NO_SLICING: + case Slic3r::GUI::NotificationManager::SlicingProgressNotification::SlicingProgressState::SP_BEGAN: m_state = EState::Hidden; set_percentage(-1); m_has_print_info = false; set_export_possible(false); - break; + m_sp_state = state; + return true; case Slic3r::GUI::NotificationManager::SlicingProgressNotification::SlicingProgressState::SP_PROGRESS: + if ((m_sp_state != SlicingProgressState::SP_BEGAN && m_sp_state != SlicingProgressState::SP_PROGRESS) || percent < m_percentage) + return false; set_percentage(percent); m_has_cancel_button = true; - break; + m_sp_state = state; + return true; case Slic3r::GUI::NotificationManager::SlicingProgressNotification::SlicingProgressState::SP_CANCELLED: set_percentage(-1); m_has_cancel_button = false; m_has_print_info = false; set_export_possible(false); - break; + m_sp_state = state; + return true; case Slic3r::GUI::NotificationManager::SlicingProgressNotification::SlicingProgressState::SP_COMPLETED: set_percentage(1); m_has_cancel_button = false; m_has_print_info = false; - // m_export_possible is important only for PROGRESS state, thus we can reset it here + // m_export_possible is important only for SP_PROGRESS state, thus we can reset it here set_export_possible(false); - break; + m_sp_state = state; + return true; default: break; } - m_sp_state = state; + return false; } void NotificationManager::SlicingProgressNotification::set_status_text(const std::string& text) { @@ -1150,7 +1172,7 @@ void NotificationManager::SlicingProgressNotification::set_status_text(const std { NotificationData data{ NotificationType::SlicingProgress, NotificationLevel::ProgressBarNotificationLevel, 0, _u8L("Slicing finished."), m_is_fff ? _u8L("Export G-Code.") : _u8L("Export.") }; update(data); - m_state = EState::Shown; + m_state = EState::NotFading; } break; default: @@ -1170,7 +1192,7 @@ void NotificationManager::SlicingProgressNotification::set_sidebar_collapsed(boo { m_sidebar_collapsed = collapsed; if (m_sp_state == SlicingProgressState::SP_COMPLETED) - m_state = EState::Shown; + m_state = EState::NotFading; } void NotificationManager::SlicingProgressNotification::on_cancel_button() @@ -1184,9 +1206,9 @@ void NotificationManager::SlicingProgressNotification::on_cancel_button() int NotificationManager::SlicingProgressNotification::get_duration() { if (m_sp_state == SlicingProgressState::SP_CANCELLED) - return 10; + return 2; else if (m_sp_state == SlicingProgressState::SP_COMPLETED && !m_sidebar_collapsed) - return 5; + return 0; else return 0; } @@ -1200,7 +1222,7 @@ bool NotificationManager::SlicingProgressNotification::update_state(bool paused } void NotificationManager::SlicingProgressNotification::render_text(ImGuiWrapper& imgui, const float win_size_x, const float win_size_y, const float win_pos_x, const float win_pos_y) { - if (m_sp_state == SlicingProgressState::SP_PROGRESS || (m_sp_state == SlicingProgressState::SP_COMPLETED && !m_sidebar_collapsed)) { + if (m_sp_state == SlicingProgressState::SP_PROGRESS /*|| (m_sp_state == SlicingProgressState::SP_COMPLETED && !m_sidebar_collapsed)*/) { ProgressBarNotification::render_text(imgui, win_size_x, win_size_y, win_pos_x, win_pos_y); /* // enable for hypertext during slicing (correct call of export_enabled needed) if (m_multiline) { @@ -1235,7 +1257,7 @@ void NotificationManager::SlicingProgressNotification::render_text(ImGuiWrapper& render_bar(imgui, win_size_x, win_size_y, win_pos_x, win_pos_y); } */ - } else if (m_sp_state == SlicingProgressState::SP_COMPLETED) { + } else if (m_sp_state == SlicingProgressState::SP_COMPLETED && m_sidebar_collapsed) { // "Slicing Finished" on line 1 + hypertext, print info on line ImVec2 win_size(win_size_x, win_size_y); ImVec2 text1_size = ImGui::CalcTextSize(m_text1.c_str()); @@ -1260,21 +1282,18 @@ void NotificationManager::SlicingProgressNotification::render_text(ImGuiWrapper& PopNotification::render_text(imgui, win_size_x, win_size_y, win_pos_x, win_pos_y); } } -void NotificationManager::SlicingProgressNotification::render_bar(ImGuiWrapper& imgui, const float win_size_x, const float win_size_y, const float win_pos_x, const float win_pos_y) +void NotificationManager::SlicingProgressNotification::render_bar(ImGuiWrapper& imgui, const float win_size_x, const float win_size_y, const float win_pos_x, const float win_pos_y) { - if (!(m_sp_state == SlicingProgressState::SP_PROGRESS || (m_sp_state == SlicingProgressState::SP_COMPLETED && !m_sidebar_collapsed))) { + if (m_sp_state != SlicingProgressState::SP_PROGRESS) { return; } - //std::string text; ProgressBarNotification::render_bar(imgui, win_size_x, win_size_y, win_pos_x, win_pos_y); - /* - std::stringstream stream; - stream << std::fixed << std::setprecision(2) << (int)(m_percentage * 100) << "%"; - text = stream.str(); - ImGui::SetCursorPosX(m_left_indentation); - ImGui::SetCursorPosY(win_size_y / 2 + win_size_y / 6 - (m_multiline ? 0 : m_line_height / 4)); - imgui.text(text.c_str()); - */ +} +void NotificationManager::SlicingProgressNotification::render_hypertext(ImGuiWrapper& imgui,const float text_x, const float text_y, const std::string text, bool more) +{ + if (m_sp_state == SlicingProgressState::SP_COMPLETED && !m_sidebar_collapsed) + return; + ProgressBarNotification::render_hypertext(imgui, text_x, text_y, text, more); } void NotificationManager::SlicingProgressNotification::render_cancel_button(ImGuiWrapper& imgui, const float win_size_x, const float win_size_y, const float win_pos_x, const float win_pos_y) { @@ -1360,7 +1379,7 @@ void NotificationManager::ProgressIndicatorNotification::init() m_state = EState::NotFading; break; case Slic3r::GUI::NotificationManager::ProgressIndicatorNotification::ProgressIndicatorState::PIS_COMPLETED: - m_state = EState::Shown; + m_state = EState::ClosePending; break; default: break; @@ -1374,7 +1393,7 @@ void NotificationManager::ProgressIndicatorNotification::set_percentage(float pe m_has_cancel_button = true; m_progress_state = ProgressIndicatorState::PIS_PROGRESS_REQUEST; } else if (percent >= 1.0f) { - m_state = EState::Shown; + m_state = EState::FadingOut; m_progress_state = ProgressIndicatorState::PIS_COMPLETED; m_has_cancel_button = false; } else { @@ -1388,6 +1407,7 @@ bool NotificationManager::ProgressIndicatorNotification::update_state(bool pause // percentage was changed (and it called schedule_extra_frame), now update must know this needs render m_next_render = 0; m_progress_state = ProgressIndicatorState::PIS_PROGRESS_UPDATED; + m_current_fade_opacity = 1.0f; return true; } bool ret = ProgressBarNotification::update_state(paused, delta); @@ -1628,6 +1648,7 @@ void NotificationManager::push_exporting_finished_notification(const std::string close_notification_of_type(NotificationType::ExportFinished); NotificationData data{ NotificationType::ExportFinished, NotificationLevel::RegularNotificationLevel, on_removable ? 0 : 20, _u8L("Exporting finished.") + "\n" + path }; push_notification_data(std::make_unique<NotificationManager::ExportFinishedNotification>(data, m_id_provider, m_evt_handler, on_removable, path, dir_path), 0); + set_slicing_progress_hidden(); } void NotificationManager::push_upload_job_notification(int id, float filesize, const std::string& filename, const std::string& host, float percentage) @@ -1700,12 +1721,39 @@ void NotificationManager::init_slicing_progress_notification(std::function<bool( }; push_notification_data(std::make_unique<NotificationManager::SlicingProgressNotification>(data, m_id_provider, m_evt_handler, cancel_callback), 0); } +void NotificationManager::set_slicing_progress_began() +{ + for (std::unique_ptr<PopNotification> & notification : m_pop_notifications) { + if (notification->get_type() == NotificationType::SlicingProgress) { + SlicingProgressNotification* spn = dynamic_cast<SlicingProgressNotification*>(notification.get()); + spn->set_progress_state(SlicingProgressNotification::SlicingProgressState::SP_BEGAN); + return; + } + } + // Slicing progress notification was not found - init it thru plater so correct cancel callback function is appended + wxGetApp().plater()->init_notification_manager(); +} void NotificationManager::set_slicing_progress_percentage(const std::string& text, float percentage) { for (std::unique_ptr<PopNotification>& notification : m_pop_notifications) { if (notification->get_type() == NotificationType::SlicingProgress) { SlicingProgressNotification* spn = dynamic_cast<SlicingProgressNotification*>(notification.get()); - spn->set_progress_state(percentage); + if(spn->set_progress_state(percentage)) { + spn->set_status_text(text); + wxGetApp().plater()->get_current_canvas3D()->schedule_extra_frame(0); + } + return; + } + } + // Slicing progress notification was not found - init it thru plater so correct cancel callback function is appended + wxGetApp().plater()->init_notification_manager(); +} +void NotificationManager::set_slicing_progress_canceled(const std::string& text) +{ + for (std::unique_ptr<PopNotification>& notification : m_pop_notifications) { + if (notification->get_type() == NotificationType::SlicingProgress) { + SlicingProgressNotification* spn = dynamic_cast<SlicingProgressNotification*>(notification.get()); + spn->set_progress_state(SlicingProgressNotification::SlicingProgressState::SP_CANCELLED); spn->set_status_text(text); wxGetApp().plater()->get_current_canvas3D()->schedule_extra_frame(0); return; @@ -1714,7 +1762,6 @@ void NotificationManager::set_slicing_progress_percentage(const std::string& tex // Slicing progress notification was not found - init it thru plater so correct cancel callback function is appended wxGetApp().plater()->init_notification_manager(); } - void NotificationManager::set_slicing_progress_hidden() { for (std::unique_ptr<PopNotification>& notification : m_pop_notifications) { @@ -1772,7 +1819,7 @@ void NotificationManager::init_progress_indicator() return; } } - NotificationData data{ NotificationType::ProgressIndicator, NotificationLevel::ProgressBarNotificationLevel, 2}; + NotificationData data{ NotificationType::ProgressIndicator, NotificationLevel::ProgressBarNotificationLevel, 1}; auto notification = std::make_unique<NotificationManager::ProgressIndicatorNotification>(data, m_id_provider, m_evt_handler); push_notification_data(std::move(notification), 0); } diff --git a/src/slic3r/GUI/NotificationManager.hpp b/src/slic3r/GUI/NotificationManager.hpp index ee510b112..4481ed701 100644 --- a/src/slic3r/GUI/NotificationManager.hpp +++ b/src/slic3r/GUI/NotificationManager.hpp @@ -189,8 +189,10 @@ public: void upload_job_notification_show_error(int id, const std::string& filename, const std::string& host); // slicing progress void init_slicing_progress_notification(std::function<bool()> cancel_callback); + void set_slicing_progress_began(); // percentage negative = canceled, <0-1) = progress, 1 = completed void set_slicing_progress_percentage(const std::string& text, float percentage); + void set_slicing_progress_canceled(const std::string& text); // hides slicing progress notification imidietly void set_slicing_progress_hidden(); // Add a print time estimate to an existing SlicingProgress notification. Set said notification to SP_COMPLETED state. @@ -492,6 +494,7 @@ private: enum class SlicingProgressState { SP_NO_SLICING, // hidden + SP_BEGAN, // still hidden but allows to go to SP_PROGRESS state. This prevents showing progress after slicing was canceled. SP_PROGRESS, // never fades outs, no close button, has cancel button SP_CANCELLED, // fades after 10 seconds, simple message SP_COMPLETED // Has export hyperlink and print info, fades after 20 sec if sidebar is shown, otherwise no fade out @@ -509,10 +512,10 @@ private: // sets cancel button callback void set_cancel_callback(std::function<bool()> callback) { m_cancel_callback = callback; } bool has_cancel_callback() const { return m_cancel_callback != nullptr; } - // sets SlicingProgressState, negative percent means canceled - void set_progress_state(float percent); - // sets SlicingProgressState, percent is used only at progress state. - void set_progress_state(SlicingProgressState state,float percent = 0.f); + // sets SlicingProgressState, negative percent means canceled, returns true if state was set succesfully. + bool set_progress_state(float percent); + // sets SlicingProgressState, percent is used only at progress state. Returns true if state was set succesfully. + bool set_progress_state(SlicingProgressState state,float percent = 0.f); // sets additional string of print info and puts notification into Completed state. void set_print_info(const std::string& info); // sets fading if in Completed state. @@ -541,8 +544,12 @@ private: const float win_size_x, const float win_size_y, const float win_pos_x, const float win_pos_y) override; 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; + const float win_size_x, const float win_size_y, + const float win_pos_x, const float win_pos_y) override; + void render_hypertext(ImGuiWrapper& imgui, + const float text_x, const float text_y, + const std::string text, + bool more = false) override ; void on_cancel_button(); int get_duration() override; // if returns false, process was already canceled @@ -626,8 +633,10 @@ private: 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; + void on_eject_click(); // local time of last hover for showing tooltip long m_hover_time { 0 }; + bool m_eject_pending { false }; }; class UpdatedItemsInfoNotification : public PopNotification diff --git a/src/slic3r/GUI/Plater.cpp b/src/slic3r/GUI/Plater.cpp index 106b4a87d..aa85c6d01 100644 --- a/src/slic3r/GUI/Plater.cpp +++ b/src/slic3r/GUI/Plater.cpp @@ -1922,6 +1922,8 @@ Plater::priv::priv(Plater *q, MainFrame *main_frame) sidebar->Bind(wxEVT_COMBOBOX, &priv::on_select_preset, this); sidebar->Bind(EVT_OBJ_LIST_OBJECT_SELECT, [this](wxEvent&) { priv::selection_changed(); }); sidebar->Bind(EVT_SCHEDULE_BACKGROUND_PROCESS, [this](SimpleEvent&) { this->schedule_background_process(); }); + // jump to found option from SearchDialog + q->Bind(wxCUSTOMEVT_JUMP_TO_OPTION, [this](wxCommandEvent& evt) { sidebar->jump_to_option(evt.GetInt()); }); } wxGLCanvas* view3D_canvas = view3D->get_wxglcanvas(); @@ -3104,6 +3106,9 @@ unsigned int Plater::priv::update_background_process(bool force_validation, bool // if ((return_state & UPDATE_BACKGROUND_PROCESS_RESTART) != 0 || // (return_state & UPDATE_BACKGROUND_PROCESS_REFRESH_SCENE) != 0 ) // this->statusbar()->set_status_text(_L("Ready to slice")); + if ((return_state & UPDATE_BACKGROUND_PROCESS_RESTART) != 0 || + (return_state & UPDATE_BACKGROUND_PROCESS_REFRESH_SCENE) != 0 ) + notification_manager->set_slicing_progress_hidden(); sidebar->set_btn_label(ActionButtonType::abExport, _(label_btn_export)); sidebar->set_btn_label(ActionButtonType::abSendGCode, _(label_btn_send)); @@ -3963,6 +3968,7 @@ void Plater::priv::on_slicing_began() clear_warnings(); notification_manager->close_notification_of_type(NotificationType::SignDetected); notification_manager->close_notification_of_type(NotificationType::ExportFinished); + notification_manager->set_slicing_progress_began(); } void Plater::priv::add_warning(const Slic3r::PrintStateBase::Warning& warning, size_t oid) { @@ -4060,7 +4066,7 @@ void Plater::priv::on_process_completed(SlicingProcessCompletedEvent &evt) } if (evt.cancelled()) { // this->statusbar()->set_status_text(_L("Cancelled")); - this->notification_manager->set_slicing_progress_percentage(_utf8("Slicing Cancelled."), -1); + this->notification_manager->set_slicing_progress_canceled(_utf8("Slicing Cancelled.")); } this->sidebar->show_sliced_info_sizer(evt.success()); @@ -6377,6 +6383,7 @@ bool Plater::set_printer_technology(PrinterTechnology printer_technology) p->sidebar->get_searcher().set_printer_technology(printer_technology); p->notification_manager->set_fff(printer_technology == ptFFF); + p->notification_manager->set_slicing_progress_hidden(); return ret; } diff --git a/src/slic3r/GUI/Search.cpp b/src/slic3r/GUI/Search.cpp index 000ebf402..1e37dc372 100644 --- a/src/slic3r/GUI/Search.cpp +++ b/src/slic3r/GUI/Search.cpp @@ -24,6 +24,8 @@ using boost::optional; namespace Slic3r { +wxDEFINE_EVENT(wxCUSTOMEVT_JUMP_TO_OPTION, wxCommandEvent); + using GUI::from_u8; using GUI::into_u8; @@ -293,8 +295,6 @@ OptionsSearcher::OptionsSearcher() OptionsSearcher::~OptionsSearcher() { - if (search_dialog) - search_dialog->Destroy(); } void OptionsSearcher::init(std::vector<InputInfo> input_values) @@ -530,9 +530,16 @@ void SearchDialog::ProcessSelection(wxDataViewItem selection) { if (!selection.IsOk()) return; - - GUI::wxGetApp().sidebar().jump_to_option(search_list_model->GetRow(selection)); this->EndModal(wxID_CLOSE); + + // If call GUI::wxGetApp().sidebar.jump_to_option() directly from here, + // then mainframe will not have focus and found option will not be "active" (have cursor) as a result + // SearchDialog have to be closed and have to lose a focus + // and only after that jump_to_option() function can be called + // So, post event to plater: + wxCommandEvent event(wxCUSTOMEVT_JUMP_TO_OPTION); + event.SetInt(search_list_model->GetRow(selection)); + wxPostEvent(GUI::wxGetApp().plater(), event); } void SearchDialog::OnInputText(wxCommandEvent&) diff --git a/src/slic3r/GUI/Search.hpp b/src/slic3r/GUI/Search.hpp index 99575e1fa..19de58f96 100644 --- a/src/slic3r/GUI/Search.hpp +++ b/src/slic3r/GUI/Search.hpp @@ -22,6 +22,8 @@ namespace Slic3r { +wxDECLARE_EVENT(wxCUSTOMEVT_JUMP_TO_OPTION, wxCommandEvent); + namespace Search{ class SearchDialog; diff --git a/src/slic3r/GUI/Tab.cpp b/src/slic3r/GUI/Tab.cpp index 4ee733942..6b7044b0d 100644 --- a/src/slic3r/GUI/Tab.cpp +++ b/src/slic3r/GUI/Tab.cpp @@ -501,6 +501,8 @@ void Tab::OnActivate() m_presets_choice->SetMinSize(ok_sz); m_presets_choice->SetSize(ok_sz); GetSizer()->GetItem(size_t(0))->GetSizer()->Layout(); + if (wxGetApp().tabs_as_menu()) + m_presets_choice->update(); } #endif // _MSW_DARK_MODE Refresh(); diff --git a/src/slic3r/GUI/UnsavedChangesDialog.cpp b/src/slic3r/GUI/UnsavedChangesDialog.cpp index 40cfa548a..ffa47ed63 100644 --- a/src/slic3r/GUI/UnsavedChangesDialog.cpp +++ b/src/slic3r/GUI/UnsavedChangesDialog.cpp @@ -1214,9 +1214,9 @@ void UnsavedChangesDialog::update(Preset::Type type, PresetCollection* dependent for (Tab* tab : wxGetApp().tabs_list) if (tab->supports_printer_technology(printer_technology) && tab->current_preset_is_dirty()) presets_cnt++; - m_action_line->SetLabel((header.IsEmpty() ? "" : header + "\n\n") + //_L("The following presets were modified:")); - + _L_PLURAL("The following preset was modified", - "The following presets were modified", presets_cnt)); + m_action_line->SetLabel((header.IsEmpty() ? "" : header + "\n\n") + + _L_PLURAL("The following preset was modified", + "The following presets were modified", presets_cnt)); } else { wxString action_msg;