mirror of
				https://github.com/SoftFever/OrcaSlicer.git
				synced 2025-10-30 20:21:12 -06:00 
			
		
		
		
	Notifications management and rendering refactoring.
With warning notification Model out of bed reworked to not show after dismiss.
This commit is contained in:
		
							parent
							
								
									08a826d237
								
							
						
					
					
						commit
						c41df487bb
					
				
					 6 changed files with 293 additions and 324 deletions
				
			
		|  | @ -845,6 +845,57 @@ bool GLVolumeCollection::check_outside_state(const DynamicPrintConfig* config, M | |||
|     return contained_min_one; | ||||
| } | ||||
| 
 | ||||
| bool GLVolumeCollection::check_outside_state(const DynamicPrintConfig* config, bool& partlyOut, bool& fullyOut) | ||||
| { | ||||
|     if (config == nullptr) | ||||
|         return false; | ||||
| 
 | ||||
|     const ConfigOptionPoints* opt = dynamic_cast<const ConfigOptionPoints*>(config->option("bed_shape")); | ||||
|     if (opt == nullptr) | ||||
|         return false; | ||||
| 
 | ||||
|     BoundingBox bed_box_2D = get_extents(Polygon::new_scale(opt->values)); | ||||
|     BoundingBoxf3 print_volume(Vec3d(unscale<double>(bed_box_2D.min(0)), unscale<double>(bed_box_2D.min(1)), 0.0), Vec3d(unscale<double>(bed_box_2D.max(0)), unscale<double>(bed_box_2D.max(1)), config->opt_float("max_print_height"))); | ||||
|     // Allow the objects to protrude below the print bed
 | ||||
|     print_volume.min(2) = -1e10; | ||||
|     print_volume.min(0) -= BedEpsilon; | ||||
|     print_volume.min(1) -= BedEpsilon; | ||||
|     print_volume.max(0) += BedEpsilon; | ||||
|     print_volume.max(1) += BedEpsilon; | ||||
| 
 | ||||
|     bool contained_min_one = false; | ||||
| 
 | ||||
|     partlyOut = false; | ||||
|     fullyOut = false; | ||||
|     for (GLVolume* volume : this->volumes) | ||||
|     { | ||||
|         if ((volume == nullptr) || volume->is_modifier || (volume->is_wipe_tower && !volume->shader_outside_printer_detection_enabled) || ((volume->composite_id.volume_id < 0) && !volume->shader_outside_printer_detection_enabled)) | ||||
|             continue; | ||||
| 
 | ||||
|         const BoundingBoxf3& bb = volume->transformed_convex_hull_bounding_box(); | ||||
|         bool contained = print_volume.contains(bb); | ||||
| 
 | ||||
|         volume->is_outside = !contained; | ||||
|         if (!volume->printable) | ||||
|             continue; | ||||
| 
 | ||||
|         if (contained) | ||||
|             contained_min_one = true; | ||||
| 
 | ||||
|         if (volume->is_outside) { | ||||
|             if (print_volume.intersects(bb)) | ||||
|                 partlyOut = true; | ||||
|             else  | ||||
|                 fullyOut = true; | ||||
|         } | ||||
|     } | ||||
|     /*
 | ||||
|     if (out_state != nullptr) | ||||
|         *out_state = state; | ||||
|     */ | ||||
|     return contained_min_one; | ||||
| } | ||||
| 
 | ||||
| void GLVolumeCollection::reset_outside_state() | ||||
| { | ||||
|     for (GLVolume* volume : this->volumes) | ||||
|  |  | |||
|  | @ -569,6 +569,7 @@ public: | |||
|     // returns true if all the volumes are completely contained in the print volume
 | ||||
|     // returns the containment state in the given out_state, if non-null
 | ||||
|     bool check_outside_state(const DynamicPrintConfig* config, ModelInstanceEPrintVolumeState* out_state); | ||||
|     bool check_outside_state(const DynamicPrintConfig* config, bool& partlyOut, bool& fullyOut); | ||||
|     void reset_outside_state(); | ||||
| 
 | ||||
|     void update_colors_by_extruder(const DynamicPrintConfig* config); | ||||
|  |  | |||
|  | @ -641,6 +641,7 @@ void GLCanvas3D::WarningTexture::activate(WarningTexture::Warning warning, bool | |||
|         error = true; | ||||
|         break; | ||||
|     } | ||||
|     BOOST_LOG_TRIVIAL(error) << state << " : " << text ; | ||||
|     auto ¬ification_manager = *wxGetApp().plater()->get_notification_manager(); | ||||
|     if (state) { | ||||
|         if(error) | ||||
|  | @ -1620,9 +1621,6 @@ void GLCanvas3D::render() | |||
|         wxGetApp().plater()->init_environment_texture(); | ||||
| #endif // ENABLE_ENVIRONMENT_MAP
 | ||||
| 
 | ||||
|     m_render_timer.Stop(); | ||||
|     m_extra_frame_requested_delayed = std::numeric_limits<int>::max(); | ||||
| 
 | ||||
|     const Size& cnv_size = get_canvas_size(); | ||||
|     // Probably due to different order of events on Linux/GTK2, when one switched from 3D scene
 | ||||
|     // to preview, this was called before canvas had its final size. It reported zero width
 | ||||
|  | @ -1754,7 +1752,7 @@ void GLCanvas3D::render() | |||
|         m_tooltip.render(m_mouse.position, *this); | ||||
| 
 | ||||
|     wxGetApp().plater()->get_mouse3d_controller().render_settings_dialog(*this); | ||||
|     wxGetApp().plater()->get_notification_manager()->render_notifications(get_overlay_window_width()); | ||||
|     wxGetApp().plater()->get_notification_manager()->render_notifications(*this, get_overlay_window_width()); | ||||
| 
 | ||||
|     wxGetApp().imgui()->render(); | ||||
| 
 | ||||
|  | @ -2238,24 +2236,24 @@ void GLCanvas3D::reload_scene(bool refresh_immediately, bool force_full_scene_re | |||
| 
 | ||||
|     // checks for geometry outside the print volume to render it accordingly
 | ||||
|     if (!m_volumes.empty()) { | ||||
|         ModelInstanceEPrintVolumeState state; | ||||
| 
 | ||||
|         const bool contained_min_one = m_volumes.check_outside_state(m_config, &state); | ||||
|         bool partlyOut = false; | ||||
|         bool fullyOut = false; | ||||
|         const bool contained_min_one = m_volumes.check_outside_state(m_config, partlyOut, fullyOut); | ||||
| 
 | ||||
| #if ENABLE_WARNING_TEXTURE_REMOVAL | ||||
|         _set_warning_notification(EWarning::ObjectClashed, state == ModelInstancePVS_Partly_Outside); | ||||
|         _set_warning_notification(EWarning::ObjectOutside, state == ModelInstancePVS_Fully_Outside); | ||||
|         if (printer_technology != ptSLA || state == ModelInstancePVS_Inside) | ||||
|         _set_warning_notification(EWarning::ObjectClashed, partlyOut); | ||||
|         _set_warning_notification(EWarning::ObjectOutside, fullyOut); | ||||
|         if (printer_technology != ptSLA || !contained_min_one) | ||||
|             _set_warning_notification(EWarning::SlaSupportsOutside, false); | ||||
| #else | ||||
|         _set_warning_texture(WarningTexture::ObjectClashed, state == ModelInstancePVS_Partly_Outside); | ||||
|         _set_warning_texture(WarningTexture::ObjectOutside, state == ModelInstancePVS_Fully_Outside); | ||||
|         if(printer_technology != ptSLA || state == ModelInstancePVS_Inside) | ||||
|         _set_warning_texture(WarningTexture::ObjectClashed, partlyOut); | ||||
|         _set_warning_texture(WarningTexture::ObjectOutside, fullyOut); | ||||
|         if(printer_technology != ptSLA || !contained_min_one) | ||||
|             _set_warning_texture(WarningTexture::SlaSupportsOutside, false); | ||||
| #endif // ENABLE_WARNING_TEXTURE_REMOVAL
 | ||||
| 
 | ||||
|         post_event(Event<bool>(EVT_GLCANVAS_ENABLE_ACTION_BUTTONS,  | ||||
|                                contained_min_one && !m_model->objects.empty() && state != ModelInstancePVS_Partly_Outside)); | ||||
|                                contained_min_one && !m_model->objects.empty() && !partlyOut)); | ||||
|     } | ||||
|     else { | ||||
| #if ENABLE_WARNING_TEXTURE_REMOVAL | ||||
|  | @ -2442,13 +2440,13 @@ void GLCanvas3D::on_idle(wxIdleEvent& evt) | |||
|     if (!m_initialized) | ||||
|         return; | ||||
| 
 | ||||
|     // FIXME
 | ||||
|     m_dirty |= m_main_toolbar.update_items_state(); | ||||
|     m_dirty |= m_undoredo_toolbar.update_items_state(); | ||||
|     m_dirty |= wxGetApp().plater()->get_view_toolbar().update_items_state(); | ||||
|     m_dirty |= wxGetApp().plater()->get_collapse_toolbar().update_items_state(); | ||||
|     bool mouse3d_controller_applied = wxGetApp().plater()->get_mouse3d_controller().apply(wxGetApp().plater()->get_camera()); | ||||
|     m_dirty |= mouse3d_controller_applied; | ||||
|     m_dirty |= wxGetApp().plater()->get_notification_manager()->update_notifications(*this); | ||||
| 
 | ||||
|     if (!m_dirty) | ||||
|         return; | ||||
|  | @ -2982,30 +2980,39 @@ void GLCanvas3D::on_timer(wxTimerEvent& evt) | |||
| 
 | ||||
| void GLCanvas3D::on_render_timer(wxTimerEvent& evt) | ||||
| { | ||||
|     // If slicer is not top window -> restart timer with one second to try again
 | ||||
|     wxWindow* p = dynamic_cast<wxWindow*>(wxGetApp().plater()); | ||||
|     while (p->GetParent() != nullptr) | ||||
|         p = p->GetParent(); | ||||
|     wxTopLevelWindow* top_level_wnd = dynamic_cast<wxTopLevelWindow*>(p); | ||||
|     if (!top_level_wnd->IsActive()) { | ||||
|         request_extra_frame_delayed(1000); | ||||
|         return; | ||||
|     } | ||||
|     //render();
 | ||||
|     m_dirty = true; | ||||
|     wxWakeUpIdle(); | ||||
|     // no need to do anything here
 | ||||
|     // right after this event is recieved, idle event is fired
 | ||||
| 
 | ||||
|     //m_dirty = true;
 | ||||
|     //wxWakeUpIdle();  
 | ||||
| } | ||||
| 
 | ||||
| void GLCanvas3D::request_extra_frame_delayed(int miliseconds) | ||||
| 
 | ||||
| void GLCanvas3D::schedule_extra_frame(int miliseconds) | ||||
| { | ||||
|     // Schedule idle event right now
 | ||||
|     if (miliseconds == 0) | ||||
|     { | ||||
|         // We want to wakeup idle evnt but most likely this is call inside render cycle so we need to wait
 | ||||
|         if (m_in_render) | ||||
|             miliseconds = 33; | ||||
|         else { | ||||
|             m_dirty = true; | ||||
|             wxWakeUpIdle(); | ||||
|             return; | ||||
|         } | ||||
|     }  | ||||
|     // Start timer
 | ||||
|     int64_t now = timestamp_now(); | ||||
|     // Timer is not running
 | ||||
|     if (! m_render_timer.IsRunning()) { | ||||
|         m_extra_frame_requested_delayed = miliseconds; | ||||
|         m_render_timer.StartOnce(miliseconds); | ||||
|         m_render_timer_start = now; | ||||
|     // Timer is running - restart only if new period is shorter than remaning period
 | ||||
|     } else { | ||||
|         const int64_t remaining_time = (m_render_timer_start + m_extra_frame_requested_delayed) - now; | ||||
|         if (miliseconds < remaining_time) { | ||||
|         if (miliseconds + 20 < remaining_time) { | ||||
|             m_render_timer.Stop();  | ||||
|             m_extra_frame_requested_delayed = miliseconds; | ||||
|             m_render_timer.StartOnce(miliseconds); | ||||
|  |  | |||
|  | @ -743,7 +743,8 @@ public: | |||
|     void msw_rescale(); | ||||
| 
 | ||||
|     void request_extra_frame() { m_extra_frame_requested = true; } | ||||
|     void request_extra_frame_delayed(int miliseconds); | ||||
|      | ||||
|     void schedule_extra_frame(int miliseconds); | ||||
| 
 | ||||
|     int get_main_toolbar_item_id(const std::string& name) const { return m_main_toolbar.get_item_id(name); } | ||||
|     void force_main_toolbar_left_action(int item_id) { m_main_toolbar.force_left_action(item_id, *this); } | ||||
|  |  | |||
|  | @ -22,9 +22,6 @@ static constexpr float SPACE_RIGHT_PANEL = 10.0f; | |||
| static constexpr float FADING_OUT_DURATION = 2.0f; | ||||
| // Time in Miliseconds after next render when fading out is requested
 | ||||
| static constexpr int   FADING_OUT_TIMEOUT = 100; | ||||
| // If timeout is changed to higher than 1 second, substract_time call should be revorked
 | ||||
| //static constexpr int   MAX_TIMEOUT_MILISECONDS = 1000; 
 | ||||
| //static constexpr int   MAX_TIMEOUT_SECONDS = 1;
 | ||||
| 
 | ||||
| namespace Slic3r { | ||||
| namespace GUI { | ||||
|  | @ -131,35 +128,29 @@ void NotificationManager::NotificationIDProvider::release_id(int) {} | |||
| NotificationManager::PopNotification::PopNotification(const NotificationData &n, NotificationIDProvider &id_provider, wxEvtHandler* evt_handler) : | ||||
| 	  m_data                (n) | ||||
| 	, m_id_provider   		(id_provider) | ||||
| 	, m_remaining_time      (n.duration) | ||||
| 	, m_last_remaining_time (n.duration) | ||||
| 	, m_counting_down       (n.duration != 0) | ||||
| 	, m_text1               (n.text1) | ||||
|     , m_hypertext           (n.hypertext) | ||||
|     , m_text2               (n.text2) | ||||
| 	, m_evt_handler         (evt_handler) | ||||
| 	, m_notification_start  (GLCanvas3D::timestamp_now()) | ||||
| { | ||||
| 	//init();
 | ||||
| } | ||||
| {} | ||||
| 
 | ||||
| void NotificationManager::PopNotification::render(GLCanvas3D& canvas, float initial_y, bool move_from_overlay, float overlay_width) | ||||
| { | ||||
| 	if (!m_initialized) | ||||
| 
 | ||||
| 	if (m_state == EState::Unknown) | ||||
| 		init(); | ||||
| 
 | ||||
| 	if (m_hidden) { | ||||
| 	if (m_state == EState::Hidden) { | ||||
| 		m_top_y = initial_y - GAP_WIDTH; | ||||
| 		return; | ||||
| 	} | ||||
| 
 | ||||
| 	if (m_fading_out)  | ||||
| 		m_last_render_fading = GLCanvas3D::timestamp_now(); | ||||
| 
 | ||||
| 	Size cnv_size = canvas.get_canvas_size(); | ||||
| 	Size          cnv_size = canvas.get_canvas_size(); | ||||
| 	ImGuiWrapper& imgui = *wxGetApp().imgui(); | ||||
| 	ImVec2 mouse_pos = ImGui::GetMousePos(); | ||||
| 	float right_gap = SPACE_RIGHT_PANEL + (move_from_overlay ? overlay_width + m_line_height * 5 : 0); | ||||
| 	ImVec2        mouse_pos = ImGui::GetMousePos(); | ||||
| 	float         right_gap = SPACE_RIGHT_PANEL + (move_from_overlay ? overlay_width + m_line_height * 5 : 0); | ||||
| 	bool          fading_pop = false; | ||||
| 
 | ||||
| 	if (m_line_height != ImGui::CalcTextSize("A").y) | ||||
| 		init(); | ||||
|  | @ -174,54 +165,46 @@ void NotificationManager::PopNotification::render(GLCanvas3D& canvas, float init | |||
| 	imgui.set_next_window_size(m_window_width, m_window_height, ImGuiCond_Always); | ||||
| 
 | ||||
| 	// find if hovered
 | ||||
| 	m_hovered = false; | ||||
| 	if (m_state == EState::Hovered)  | ||||
| 		m_state = EState::Shown; | ||||
| 
 | ||||
| 	if (mouse_pos.x < win_pos.x && mouse_pos.x > win_pos.x - m_window_width && mouse_pos.y > win_pos.y && mouse_pos.y < win_pos.y + m_window_height) { | ||||
| 		ImGui::SetNextWindowFocus(); | ||||
| 		m_hovered = true; | ||||
| 		m_state = EState::Hovered; | ||||
| 	} | ||||
| 
 | ||||
| 	 | ||||
| 	// color change based on fading out
 | ||||
| 	bool fading_pop = false; | ||||
| 	if (m_fading_out) { | ||||
| 		Notifications_Internal::push_style_color(ImGuiCol_WindowBg, ImGui::GetStyleColorVec4(ImGuiCol_WindowBg), m_fading_out, m_current_fade_opacity); | ||||
| 		Notifications_Internal::push_style_color(ImGuiCol_Text, ImGui::GetStyleColorVec4(ImGuiCol_Text), m_fading_out, m_current_fade_opacity); | ||||
| 	if (m_state == EState::FadingOut) { | ||||
| 		Notifications_Internal::push_style_color(ImGuiCol_WindowBg, ImGui::GetStyleColorVec4(ImGuiCol_WindowBg), true, m_current_fade_opacity); | ||||
| 		Notifications_Internal::push_style_color(ImGuiCol_Text, ImGui::GetStyleColorVec4(ImGuiCol_Text), true, m_current_fade_opacity); | ||||
| 		fading_pop = true; | ||||
| 	} | ||||
| 
 | ||||
| 	 | ||||
| 	// background color
 | ||||
| 	if (m_is_gray) { | ||||
| 		ImVec4 backcolor(0.7f, 0.7f, 0.7f, 0.5f); | ||||
| 		Notifications_Internal::push_style_color(ImGuiCol_WindowBg, backcolor, m_fading_out, m_current_fade_opacity); | ||||
| 		Notifications_Internal::push_style_color(ImGuiCol_WindowBg, backcolor, m_state == EState::FadingOut, m_current_fade_opacity); | ||||
| 	} | ||||
| 	else if (m_data.level == NotificationLevel::ErrorNotification) { | ||||
| 		ImVec4 backcolor = ImGui::GetStyleColorVec4(ImGuiCol_WindowBg); | ||||
| 		backcolor.x += 0.3f; | ||||
| 		Notifications_Internal::push_style_color(ImGuiCol_WindowBg, backcolor, m_fading_out, m_current_fade_opacity); | ||||
| 		Notifications_Internal::push_style_color(ImGuiCol_WindowBg, backcolor, m_state == EState::FadingOut, m_current_fade_opacity); | ||||
| 	} | ||||
| 	else if (m_data.level == NotificationLevel::WarningNotification) { | ||||
| 		ImVec4 backcolor = ImGui::GetStyleColorVec4(ImGuiCol_WindowBg); | ||||
| 		backcolor.x += 0.3f; | ||||
| 		backcolor.y += 0.15f; | ||||
| 		Notifications_Internal::push_style_color(ImGuiCol_WindowBg, backcolor, m_fading_out, m_current_fade_opacity); | ||||
| 		Notifications_Internal::push_style_color(ImGuiCol_WindowBg, backcolor, m_state == EState::FadingOut, m_current_fade_opacity); | ||||
| 	} | ||||
| 
 | ||||
| 	// name of window - probably indentifies window and is shown so last_end add whitespaces according to id
 | ||||
| 	 | ||||
| 	// name of window indentifies window - has to be unique string
 | ||||
| 	if (m_id == 0) | ||||
| 		m_id = m_id_provider.allocate_id(); | ||||
| 	std::string name = "!!Ntfctn" + std::to_string(m_id); | ||||
| 	 | ||||
| 	if (imgui.begin(name, ImGuiWindowFlags_NoCollapse | ImGuiWindowFlags_NoTitleBar | ImGuiWindowFlags_NoMove | ImGuiWindowFlags_NoResize | ImGuiWindowFlags_NoScrollbar)) { | ||||
| 		ImVec2 win_size = ImGui::GetWindowSize(); | ||||
| 
 | ||||
| 		//FIXME: dont forget to us this for texts
 | ||||
| 		//GUI::format(_utf8(L()));
 | ||||
| 
 | ||||
| 		/*
 | ||||
| 		//countdown numbers
 | ||||
| 		ImGui::SetCursorPosX(15); | ||||
| 		ImGui::SetCursorPosY(15); | ||||
| 		imgui.text(std::to_string(m_remaining_time).c_str()); | ||||
| 		*/ | ||||
| 
 | ||||
| 		render_left_sign(imgui); | ||||
| 		render_text(imgui, win_size.x, win_size.y, win_pos.x, win_pos.y); | ||||
| 		render_close_button(imgui, win_size.x, win_size.y, win_pos.x, win_pos.y); | ||||
|  | @ -253,6 +236,7 @@ void NotificationManager::PopNotification::count_spaces() | |||
| 	m_window_width_offset = m_left_indentation + m_line_height * 3.f; | ||||
| 	m_window_width = m_line_height * 25; | ||||
| } | ||||
|   | ||||
| void NotificationManager::PopNotification::init() | ||||
| { | ||||
|     std::string text          = m_text1 + " " + m_hypertext; | ||||
|  | @ -306,7 +290,7 @@ void NotificationManager::PopNotification::init() | |||
| 	} | ||||
| 	if (m_lines_count == 3) | ||||
| 		m_multiline = true; | ||||
| 	m_initialized = true; | ||||
| 	m_state = EState::Shown; | ||||
| } | ||||
| void NotificationManager::PopNotification::set_next_window_size(ImGuiWrapper& imgui) | ||||
| {  | ||||
|  | @ -423,8 +407,8 @@ void NotificationManager::PopNotification::render_hypertext(ImGuiWrapper& imgui, | |||
| 			m_multiline = true; | ||||
| 			set_next_window_size(imgui); | ||||
| 		} | ||||
| 		else { | ||||
| 			m_close_pending = on_text_click(); | ||||
| 		else if (on_text_click()) { | ||||
| 			close(); | ||||
| 		} | ||||
| 	} | ||||
| 	ImGui::PopStyleColor(); | ||||
|  | @ -432,12 +416,12 @@ void NotificationManager::PopNotification::render_hypertext(ImGuiWrapper& imgui, | |||
| 	ImGui::PopStyleColor(); | ||||
| 
 | ||||
| 	//hover color
 | ||||
| 	ImVec4 orange_color = ImVec4(.99f, .313f, .0f, 1.0f);//ImGui::GetStyleColorVec4(ImGuiCol_Button);
 | ||||
| 	ImVec4 orange_color = ImVec4(.99f, .313f, .0f, 1.0f); | ||||
| 	if (ImGui::IsItemHovered(ImGuiHoveredFlags_RectOnly)) | ||||
| 		orange_color.y += 0.2f; | ||||
| 
 | ||||
| 	//text
 | ||||
| 	Notifications_Internal::push_style_color(ImGuiCol_Text, orange_color, m_fading_out, m_current_fade_opacity); | ||||
| 	Notifications_Internal::push_style_color(ImGuiCol_Text, orange_color, m_state == EState::FadingOut, m_current_fade_opacity); | ||||
| 	ImGui::SetCursorPosX(text_x); | ||||
| 	ImGui::SetCursorPosY(text_y); | ||||
| 	imgui.text(text.c_str()); | ||||
|  | @ -448,7 +432,7 @@ void NotificationManager::PopNotification::render_hypertext(ImGuiWrapper& imgui, | |||
| 	lineEnd.y -= 2; | ||||
| 	ImVec2 lineStart = lineEnd; | ||||
| 	lineStart.x = ImGui::GetItemRectMin().x; | ||||
| 	ImGui::GetWindowDrawList()->AddLine(lineStart, lineEnd, IM_COL32((int)(orange_color.x * 255), (int)(orange_color.y * 255), (int)(orange_color.z * 255), (int)(orange_color.w * 255.f * (m_fading_out ? m_current_fade_opacity : 1.f)))); | ||||
| 	ImGui::GetWindowDrawList()->AddLine(lineStart, lineEnd, IM_COL32((int)(orange_color.x * 255), (int)(orange_color.y * 255), (int)(orange_color.z * 255), (int)(orange_color.w * 255.f * (m_state == EState::FadingOut ? m_current_fade_opacity : 1.f)))); | ||||
| 
 | ||||
| } | ||||
| 
 | ||||
|  | @ -458,12 +442,11 @@ void NotificationManager::PopNotification::render_close_button(ImGuiWrapper& img | |||
| 	ImVec2 win_pos(win_pos_x, win_pos_y);  | ||||
| 	ImGui::PushStyleColor(ImGuiCol_Button, ImVec4(.0f, .0f, .0f, .0f)); | ||||
| 	ImGui::PushStyleColor(ImGuiCol_ButtonHovered, ImVec4(.0f, .0f, .0f, .0f)); | ||||
| 	Notifications_Internal::push_style_color(ImGuiCol_Text, ImVec4(1.f, 1.f, 1.f, 1.f), m_fading_out, m_current_fade_opacity); | ||||
| 	Notifications_Internal::push_style_color(ImGuiCol_TextSelectedBg, ImVec4(0, .75f, .75f, 1.f), m_fading_out, m_current_fade_opacity); | ||||
| 	Notifications_Internal::push_style_color(ImGuiCol_Text, ImVec4(1.f, 1.f, 1.f, 1.f), m_state == EState::FadingOut, m_current_fade_opacity); | ||||
| 	Notifications_Internal::push_style_color(ImGuiCol_TextSelectedBg, ImVec4(0, .75f, .75f, 1.f), m_state == EState::FadingOut, m_current_fade_opacity); | ||||
| 	ImGui::PushStyleColor(ImGuiCol_ButtonActive, ImVec4(.0f, .0f, .0f, .0f)); | ||||
| 
 | ||||
| 
 | ||||
| 	//button - if part if treggered
 | ||||
| 	std::string button_text; | ||||
| 	button_text = ImGui::CloseNotifButton; | ||||
| 	 | ||||
|  | @ -479,7 +462,7 @@ void NotificationManager::PopNotification::render_close_button(ImGuiWrapper& img | |||
| 	ImGui::SetCursorPosY(win_size.y / 2 - button_size.y); | ||||
| 	if (imgui.button(button_text.c_str(), button_size.x, button_size.y)) | ||||
| 	{ | ||||
| 		m_close_pending = true; | ||||
| 		close(); | ||||
| 	} | ||||
| 
 | ||||
| 	//invisible large button
 | ||||
|  | @ -487,7 +470,7 @@ void NotificationManager::PopNotification::render_close_button(ImGuiWrapper& img | |||
| 	ImGui::SetCursorPosY(0); | ||||
| 	if (imgui.button(" ", m_line_height * 2.125, win_size.y - ( m_minimize_b_visible ? 2 * m_line_height : 0))) | ||||
| 	{ | ||||
| 		m_close_pending = true; | ||||
| 		close(); | ||||
| 	} | ||||
| 	ImGui::PopStyleColor(); | ||||
| 	ImGui::PopStyleColor(); | ||||
|  | @ -510,9 +493,9 @@ void NotificationManager::PopNotification::render_minimize_button(ImGuiWrapper& | |||
| { | ||||
| 	ImGui::PushStyleColor(ImGuiCol_Button, ImVec4(.0f, .0f, .0f, .0f)); | ||||
| 	ImGui::PushStyleColor(ImGuiCol_ButtonHovered, ImVec4(.0f, .0f, .0f, .0f)); | ||||
| 	Notifications_Internal::push_style_color(ImGuiCol_ButtonActive, ImGui::GetStyleColorVec4(ImGuiCol_WindowBg), m_fading_out, m_current_fade_opacity); | ||||
| 	Notifications_Internal::push_style_color(ImGuiCol_Text, ImVec4(1.f, 1.f, 1.f, 1.f), m_fading_out, m_current_fade_opacity); | ||||
| 	Notifications_Internal::push_style_color(ImGuiCol_TextSelectedBg, ImVec4(0, .75f, .75f, 1.f), m_fading_out, m_current_fade_opacity); | ||||
| 	Notifications_Internal::push_style_color(ImGuiCol_ButtonActive, ImGui::GetStyleColorVec4(ImGuiCol_WindowBg), m_state == EState::FadingOut, m_current_fade_opacity); | ||||
| 	Notifications_Internal::push_style_color(ImGuiCol_Text, ImVec4(1.f, 1.f, 1.f, 1.f), m_state == EState::FadingOut, m_current_fade_opacity); | ||||
| 	Notifications_Internal::push_style_color(ImGuiCol_TextSelectedBg, ImVec4(0, .75f, .75f, 1.f), m_state == EState::FadingOut, m_current_fade_opacity); | ||||
| 
 | ||||
| 	 | ||||
| 	//button - if part if treggered
 | ||||
|  | @ -564,71 +547,56 @@ bool NotificationManager::PopNotification::compare_text(const std::string& text) | |||
| 	return false; | ||||
| } | ||||
| 
 | ||||
| void NotificationManager::PopNotification::update_state() | ||||
| void NotificationManager::PopNotification::update_state(bool paused, const int64_t delta) | ||||
| { | ||||
| 	if (!m_initialized) | ||||
| 	if (m_state == EState::Unknown) | ||||
| 		init(); | ||||
| 
 | ||||
| 	m_next_render = std::numeric_limits<int64_t>::max(); | ||||
| 
 | ||||
| 	if (m_hidden) { | ||||
| 		m_state = EState::Hidden; | ||||
| 	if (m_state == EState::Hidden) { | ||||
| 		return; | ||||
| 	} | ||||
| 
 | ||||
| 	int64_t now = GLCanvas3D::timestamp_now(); | ||||
| 
 | ||||
| 	if (m_hovered) { | ||||
| 		// reset fading
 | ||||
| 		m_fading_out = false; | ||||
| 	// reset timers - hovered state is set in render 
 | ||||
| 	if (m_state == EState::Hovered) {  | ||||
| 		m_current_fade_opacity = 1.0f; | ||||
| 		m_remaining_time = m_data.duration; | ||||
| 		m_notification_start = now; | ||||
| 	} | ||||
| 
 | ||||
| 	 | ||||
| 
 | ||||
| 	if (m_counting_down) { | ||||
| 	// Timers when not fading
 | ||||
| 	} else if (m_data.duration != 0 && !paused) { | ||||
| 		int64_t up_time = now - m_notification_start; | ||||
| 
 | ||||
| 		if (m_fading_out && m_current_fade_opacity <= 0.0f) | ||||
| 			m_finished = true; | ||||
| 		else if (!m_fading_out && /*m_remaining_time <=0*/up_time >= m_data.duration * 1000) { | ||||
| 			m_fading_out = true; | ||||
| 			m_fading_start = now; | ||||
| 			m_last_render_fading = now; | ||||
| 		} else if (!m_fading_out) { | ||||
| 			m_next_render = m_data.duration * 1000 - up_time;//std::min<int64_t>(/*m_data.duration * 1000 - up_time*/m_remaining_time * 1000, MAX_TIMEOUT_MILISECONDS);
 | ||||
| 		} | ||||
| 		 | ||||
| 		if (m_state != EState::FadingOut && up_time >= m_data.duration * 1000) { | ||||
| 			m_state					= EState::FadingOut; | ||||
| 			m_fading_start			= now; | ||||
| 		} else if (m_state != EState::FadingOut) { | ||||
| 			m_next_render = m_data.duration * 1000 - up_time; | ||||
| 		}	 | ||||
| 	} | ||||
| 	 | ||||
| 	if (m_finished) { | ||||
| 	// Timers when fading
 | ||||
| 	if (m_state == EState::FadingOut && !paused) { | ||||
| 		int64_t curr_time		= now - m_fading_start; | ||||
| 		int64_t next_render		= FADING_OUT_TIMEOUT - delta; | ||||
| 		m_current_fade_opacity	= std::clamp(1.0f - 0.001f * static_cast<float>(curr_time) / FADING_OUT_DURATION, 0.0f, 1.0f); | ||||
| 		if (m_current_fade_opacity <= 0.0f) | ||||
| 			m_state = EState::Finished; | ||||
| 		else if (next_render < 0)  | ||||
| 			m_next_render = 0; | ||||
| 		else | ||||
| 			m_next_render = next_render; | ||||
| 	} | ||||
| 
 | ||||
| 	if (m_state == EState::Finished) { | ||||
| 		m_next_render = 0; | ||||
| 		return; | ||||
| 	} | ||||
| 
 | ||||
| 	if (m_state == EState::ClosePending) { | ||||
| 		m_state = EState::Finished; | ||||
| 		m_next_render = 0; | ||||
| 		return; | ||||
| 	} | ||||
| 	if (m_close_pending) { | ||||
| 		m_finished = true; | ||||
| 		m_state = EState::ClosePending; | ||||
| 		m_next_render = 0; | ||||
| 		return; | ||||
| 	} | ||||
| 	if (m_fading_out) { | ||||
| 		if (!m_paused) { | ||||
| 			m_state = EState::FadingOutStatic; | ||||
| 			int64_t curr_time      = now - m_fading_start; | ||||
| 			int64_t no_render_time = now - m_last_render_fading; | ||||
| 			m_current_fade_opacity = std::clamp(1.0f - 0.001f * static_cast<float>(curr_time) / FADING_OUT_DURATION, 0.0f, 1.0f); | ||||
| 			auto next_render = FADING_OUT_TIMEOUT - no_render_time; | ||||
| 			if (next_render <= 0) { | ||||
| 				//m_last_render_fading = GLCanvas3D::timestamp_now();
 | ||||
| 				m_state = EState::FadingOutRender; | ||||
| 				m_next_render = 0; | ||||
| 			} else  | ||||
| 				m_next_render = next_render; | ||||
| 		} | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| NotificationManager::SlicingCompleteLargeNotification::SlicingCompleteLargeNotification(const NotificationData& n, NotificationIDProvider& id_provider, wxEvtHandler* evt_handler, bool large) : | ||||
|  | @ -672,9 +640,10 @@ void NotificationManager::SlicingCompleteLargeNotification::set_print_info(const | |||
| void NotificationManager::SlicingCompleteLargeNotification::set_large(bool l) | ||||
| { | ||||
| 	m_is_large = l; | ||||
| 	m_counting_down = !l; | ||||
| 	//FIXME this information should not be lost (change m_data?)
 | ||||
| //	m_counting_down = !l;
 | ||||
| 	m_hypertext = l ? _u8L("Export G-Code.") : std::string(); | ||||
| 	m_hidden = !l; | ||||
| 	m_state = l ? EState::Shown : EState::Hidden; | ||||
| } | ||||
| //---------------ExportFinishedNotification-----------
 | ||||
| void NotificationManager::ExportFinishedNotification::count_spaces() | ||||
|  | @ -733,8 +702,8 @@ void NotificationManager::ExportFinishedNotification::render_eject_button(ImGuiW | |||
| 	ImVec2 win_pos(win_pos_x, win_pos_y); | ||||
| 	ImGui::PushStyleColor(ImGuiCol_Button, ImVec4(.0f, .0f, .0f, .0f)); | ||||
| 	ImGui::PushStyleColor(ImGuiCol_ButtonHovered, ImVec4(.0f, .0f, .0f, .0f)); | ||||
| 	Notifications_Internal::push_style_color(ImGuiCol_Text, ImVec4(1.f, 1.f, 1.f, 1.f), m_fading_out, m_current_fade_opacity); | ||||
| 	Notifications_Internal::push_style_color(ImGuiCol_TextSelectedBg, ImVec4(0, .75f, .75f, 1.f), m_fading_out, m_current_fade_opacity); | ||||
| 	Notifications_Internal::push_style_color(ImGuiCol_Text, ImVec4(1.f, 1.f, 1.f, 1.f), m_state == EState::FadingOut, m_current_fade_opacity); | ||||
| 	Notifications_Internal::push_style_color(ImGuiCol_TextSelectedBg, ImVec4(0, .75f, .75f, 1.f), m_state == EState::FadingOut, m_current_fade_opacity); | ||||
| 	ImGui::PushStyleColor(ImGuiCol_ButtonActive, ImVec4(.0f, .0f, .0f, .0f)); | ||||
| 
 | ||||
| 	std::string button_text; | ||||
|  | @ -768,7 +737,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)); | ||||
| 		m_close_pending = true; | ||||
| 		close(); | ||||
| 	} | ||||
| 
 | ||||
| 	//invisible large button
 | ||||
|  | @ -779,7 +748,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)); | ||||
| 		m_close_pending = true; | ||||
| 		close(); | ||||
| 	} | ||||
| 	ImGui::PopStyleColor(); | ||||
| 	ImGui::PopStyleColor(); | ||||
|  | @ -807,22 +776,12 @@ void NotificationManager::ProgressBarNotification::render_text(ImGuiWrapper& img | |||
| void NotificationManager::ProgressBarNotification::render_bar(ImGuiWrapper& imgui, const float win_size_x, const float win_size_y, const float win_pos_x, const float win_pos_y) | ||||
| { | ||||
| 	ImVec4 orange_color = ImVec4(.99f, .313f, .0f, 1.0f); | ||||
| 	float  invisible_length = 0;//((float)(m_data.duration - m_remaining_time) / (float)m_data.duration * win_size_x);
 | ||||
| 	//invisible_length -= win_size_x / ((float)m_data.duration * 60.f) * (60 - m_countdown_frame);
 | ||||
| 	float  invisible_length = 0; | ||||
| 
 | ||||
| 	ImVec2 lineEnd = ImVec2(win_pos_x - invisible_length - m_window_width_offset, win_pos_y + win_size_y/2 + m_line_height / 2); | ||||
| 	ImVec2 lineStart = ImVec2(win_pos_x - win_size_x + m_left_indentation, win_pos_y + win_size_y/2 + m_line_height / 2); | ||||
| 	ImGui::GetWindowDrawList()->AddLine(lineStart, lineEnd, IM_COL32((int)(orange_color.x * 255), (int)(orange_color.y * 255), (int)(orange_color.z * 255), (1.0f * 255.f)), m_line_height * 0.7f); | ||||
| 	/*
 | ||||
| 	//countdown line
 | ||||
| 	ImVec4 orange_color = ImGui::GetStyleColorVec4(ImGuiCol_Button); | ||||
| 	float  invisible_length = ((float)(m_data.duration - m_remaining_time) / (float)m_data.duration * win_size_x); | ||||
| 	invisible_length -= win_size_x / ((float)m_data.duration * 60.f) * (60 - m_countdown_frame); | ||||
| 	ImVec2 lineEnd = ImVec2(win_pos_x - invisible_length, win_pos_y + win_size_y - 5); | ||||
| 	ImVec2 lineStart = ImVec2(win_pos_x - win_size_x, win_pos_y + win_size_y - 5); | ||||
| 	ImGui::GetWindowDrawList()->AddLine(lineStart, lineEnd, IM_COL32((int)(orange_color.x * 255), (int)(orange_color.y * 255), (int)(orange_color.z * 255), (int)(orange_color.picture_width * 255.f * (m_fading_out ? m_current_fade_opacity : 1.f))), 2.f); | ||||
| 	if (!m_paused) | ||||
| 		m_countdown_frame++; | ||||
| 		*/ | ||||
| 
 | ||||
| } | ||||
| //------NotificationManager--------
 | ||||
| NotificationManager::NotificationManager(wxEvtHandler* evt_handler) : | ||||
|  | @ -881,12 +840,7 @@ void NotificationManager::push_plater_error_notification(const std::string& text | |||
| { | ||||
| 	push_notification_data({ NotificationType::PlaterError, NotificationLevel::ErrorNotification, 0,  _u8L("ERROR:") + "\n" + text }, 0); | ||||
| } | ||||
| void NotificationManager::push_plater_warning_notification(const std::string& text) | ||||
| { | ||||
| 	push_notification_data({ NotificationType::PlaterWarning, NotificationLevel::WarningNotification, 0,  _u8L("WARNING:") + "\n" + text }, 0); | ||||
| 	// dissaper if in preview
 | ||||
| 	set_in_preview(m_in_preview); | ||||
| } | ||||
| 
 | ||||
| void NotificationManager::close_plater_error_notification(const std::string& text) | ||||
| { | ||||
| 	for (std::unique_ptr<PopNotification> ¬ification : m_pop_notifications) { | ||||
|  | @ -895,11 +849,32 @@ void NotificationManager::close_plater_error_notification(const std::string& tex | |||
| 		} | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| void NotificationManager::push_plater_warning_notification(const std::string& text) | ||||
| { | ||||
| 	// Find if was not hidden 
 | ||||
| 	for (std::unique_ptr<PopNotification>& notification : m_pop_notifications) { | ||||
| 		if (notification->get_type() == NotificationType::PlaterWarning && notification->compare_text(_u8L("WARNING:") + "\n" + text)) { | ||||
| 			if (notification->get_state() == PopNotification::EState::Hidden) { | ||||
| 				//dynamic_cast<PlaterWarningNotification*>(notification.get())->show();
 | ||||
| 				return; | ||||
| 			} | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	NotificationData data{ NotificationType::PlaterWarning, NotificationLevel::WarningNotification, 0,  _u8L("WARNING:") + "\n" + text }; | ||||
| 
 | ||||
| 	auto notification = std::make_unique<NotificationManager::PlaterWarningNotification>(data, m_id_provider, m_evt_handler); | ||||
| 	push_notification_data(std::move(notification), 0); | ||||
| 	// dissaper if in preview
 | ||||
| 	set_in_preview(m_in_preview); | ||||
| } | ||||
| 
 | ||||
| void NotificationManager::close_plater_warning_notification(const std::string& text) | ||||
| { | ||||
| 	for (std::unique_ptr<PopNotification> ¬ification : m_pop_notifications) { | ||||
| 		if (notification->get_type() == NotificationType::PlaterWarning && notification->compare_text(_u8L("WARNING:") + "\n" + text)) { | ||||
| 			notification->close(); | ||||
| 			dynamic_cast<PlaterWarningNotification*>(notification.get())->real_close(); | ||||
| 		} | ||||
| 	} | ||||
| } | ||||
|  | @ -1008,7 +983,8 @@ void NotificationManager::set_progress_bar_percentage(const std::string& text, f | |||
| 	for (std::unique_ptr<PopNotification>& notification : m_pop_notifications) { | ||||
| 		if (notification->get_type() == NotificationType::ProgressBar && notification->compare_text(text)) { | ||||
| 			dynamic_cast<ProgressBarNotification*>(notification.get())->set_percentage(percentage); | ||||
| 			wxGetApp().plater()->get_current_canvas3D()->request_extra_frame(); | ||||
| 			// FIX ME: this is massive gpu eater (render every frame)
 | ||||
| 			wxGetApp().plater()->get_current_canvas3D()->schedule_extra_frame(0); | ||||
| 			found = true; | ||||
| 		} | ||||
| 	} | ||||
|  | @ -1035,20 +1011,19 @@ bool NotificationManager::push_notification_data(std::unique_ptr<NotificationMan | |||
| 
 | ||||
| 	if (this->activate_existing(notification.get())) { | ||||
| 		m_pop_notifications.back()->update(notification->get_data()); | ||||
| 		canvas.request_extra_frame_delayed(33); | ||||
| 		canvas.schedule_extra_frame(0); | ||||
| 		return false; | ||||
| 	} else { | ||||
| 		m_pop_notifications.emplace_back(std::move(notification)); | ||||
| 		canvas.request_extra_frame_delayed(33); | ||||
| 		canvas.schedule_extra_frame(0); | ||||
| 		return true; | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| void NotificationManager::render_notifications(float overlay_width) | ||||
| void NotificationManager::render_notifications(GLCanvas3D& canvas, float overlay_width) | ||||
| { | ||||
| 	sort_notifications(); | ||||
| 
 | ||||
| 	GLCanvas3D& canvas = *wxGetApp().plater()->get_current_canvas3D(); | ||||
| 	 | ||||
| 	float last_y = 0.0f; | ||||
| 
 | ||||
| 	for (const auto& notification : m_pop_notifications) { | ||||
|  | @ -1059,9 +1034,54 @@ void NotificationManager::render_notifications(float overlay_width) | |||
| 		} | ||||
| 		 | ||||
| 	} | ||||
| 	update_notifications(); | ||||
| 	m_last_render = GLCanvas3D::timestamp_now(); | ||||
| } | ||||
| 
 | ||||
| bool NotificationManager::update_notifications(GLCanvas3D& canvas) | ||||
| { | ||||
| 	// no update if not top window
 | ||||
| 	wxWindow* p = dynamic_cast<wxWindow*>(wxGetApp().plater()); | ||||
| 	while (p->GetParent() != nullptr) | ||||
| 		p = p->GetParent(); | ||||
| 	wxTopLevelWindow* top_level_wnd = dynamic_cast<wxTopLevelWindow*>(p); | ||||
| 	if (!top_level_wnd->IsActive()) | ||||
| 		return false; | ||||
| 
 | ||||
| 	// next_render() returns numeric_limits::max if no need for frame
 | ||||
| 	const int64_t max = std::numeric_limits<int64_t>::max(); | ||||
| 	int64_t       next_render = max; | ||||
| 	const int64_t time_since_render = GLCanvas3D::timestamp_now() - m_last_render; | ||||
| 	// During render, each notification detects if its currently hovered and changes its state to EState::Hovered
 | ||||
| 	// If any notification is hovered, all restarts its countdown 
 | ||||
| 	bool          hover = false; | ||||
| 	for (const std::unique_ptr<PopNotification>& notification : m_pop_notifications) { | ||||
| 		if (notification->is_hovered()) { | ||||
| 			hover = true; | ||||
| 			break; | ||||
| 		} | ||||
| 	} | ||||
| 	// update state of all notif and erase finished
 | ||||
| 	for (auto it = m_pop_notifications.begin(); it != m_pop_notifications.end();) { | ||||
| 		std::unique_ptr<PopNotification>& notification = *it; | ||||
| 		notification->update_state(hover, time_since_render); | ||||
| 		next_render = std::min<int64_t>(next_render, notification->next_render()); | ||||
| 		if (notification->get_state() == PopNotification::EState::Finished) | ||||
| 			it = m_pop_notifications.erase(it); | ||||
| 		else  | ||||
| 			++it; | ||||
| 	} | ||||
| 
 | ||||
| 	// render needed right now
 | ||||
| 	if (next_render < 20) | ||||
| 		return true; | ||||
| 	// request next frame 
 | ||||
| 	if (next_render < max) | ||||
| 		canvas.schedule_extra_frame(int(next_render)); | ||||
| 
 | ||||
| 	return false; | ||||
| } | ||||
| >>>>>>> 6df0d8ff81... Notifications management and rendering  refactoring. | ||||
| 
 | ||||
| void NotificationManager::sort_notifications() | ||||
| { | ||||
| 	// Stable sorting, so that the order of equal ranges is stable.
 | ||||
|  | @ -1112,103 +1132,6 @@ void NotificationManager::set_in_preview(bool preview) | |||
|     } | ||||
| } | ||||
| 
 | ||||
| void NotificationManager::update_notifications() | ||||
| { | ||||
| 	// no update if not top window
 | ||||
| 	wxWindow* p = dynamic_cast<wxWindow*>(wxGetApp().plater()); | ||||
| 	while (p->GetParent() != nullptr) | ||||
| 		p = p->GetParent(); | ||||
| 	wxTopLevelWindow* top_level_wnd = dynamic_cast<wxTopLevelWindow*>(p); | ||||
| 	if (!top_level_wnd->IsActive()) | ||||
| 		return; | ||||
| 
 | ||||
| 	//static size_t last_size = m_pop_notifications.size();
 | ||||
| 
 | ||||
| 	//request frames
 | ||||
| 	int64_t next_render = std::numeric_limits<int64_t>::max(); | ||||
| 	for (auto it = m_pop_notifications.begin(); it != m_pop_notifications.end();) { | ||||
| 		std::unique_ptr<PopNotification>& notification = *it; | ||||
| 		notification->set_paused(m_hovered); | ||||
| 		notification->update_state(); | ||||
| 		next_render = std::min<int64_t>(next_render, notification->next_render()); | ||||
| 		if (notification->get_state() == PopNotification::EState::Finished) | ||||
| 			it = m_pop_notifications.erase(it); | ||||
| 		else { | ||||
| 			 | ||||
| 			++it; | ||||
| 		} | ||||
| 	} | ||||
| 	/*
 | ||||
| 	m_requires_update = false; | ||||
| 	for (const std::unique_ptr<PopNotification>& notification : m_pop_notifications) { | ||||
| 		if (notification->requires_update()) { | ||||
| 			m_requires_update = true; | ||||
| 			break; | ||||
| 		} | ||||
| 	} | ||||
| 	*/ | ||||
| 	// update hovering state
 | ||||
| 	m_hovered = false; | ||||
| 	for (const std::unique_ptr<PopNotification>& notification : m_pop_notifications) { | ||||
| 		if (notification->is_hovered()) { | ||||
| 			m_hovered = true; | ||||
| 			break; | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	/*
 | ||||
| 	// Reuire render if some notification was just deleted.
 | ||||
| 	size_t curr_size = m_pop_notifications.size(); | ||||
| 	m_requires_render = m_hovered || (last_size != curr_size); | ||||
| 	last_size = curr_size; | ||||
| 
 | ||||
| 	// Ask notification if it needs render
 | ||||
| 	if (!m_requires_render) { | ||||
| 		for (const std::unique_ptr<PopNotification>& notification : m_pop_notifications) { | ||||
| 			if (notification->requires_render()) { | ||||
| 				m_requires_render = true; | ||||
| 				break; | ||||
| 			} | ||||
| 		} | ||||
| 	} | ||||
| 	// Make sure there will be update after last notification erased
 | ||||
| 	if (m_requires_render) | ||||
| 		m_requires_update = true; | ||||
| 	*/ | ||||
| 	 | ||||
| 
 | ||||
| 	if (next_render == 0) | ||||
| 		wxGetApp().plater()->get_current_canvas3D()->request_extra_frame_delayed(33); //few milliseconds to get from GLCanvas::render
 | ||||
| 	else if (next_render < std::numeric_limits<int64_t>::max()) | ||||
| 		wxGetApp().plater()->get_current_canvas3D()->request_extra_frame_delayed(int(next_render)); | ||||
| 
 | ||||
| 	/*
 | ||||
| 	// actualizate timers
 | ||||
| 	wxWindow* p = dynamic_cast<wxWindow*>(wxGetApp().plater()); | ||||
| 	while (p->GetParent() != nullptr) | ||||
| 		p = p->GetParent(); | ||||
| 	wxTopLevelWindow* top_level_wnd = dynamic_cast<wxTopLevelWindow*>(p); | ||||
| 	if (!top_level_wnd->IsActive()) | ||||
| 		return; | ||||
| 
 | ||||
| 	{ | ||||
| 		// Control the fade-out.
 | ||||
| 		// time in seconds
 | ||||
| 		long now = wxGetLocalTime(); | ||||
| 		// Pausing fade-out when the mouse is over some notification.
 | ||||
| 		if (!m_hovered && m_last_time < now) { | ||||
| 			if (now - m_last_time >= MAX_TIMEOUT_SECONDS) { | ||||
| 				for (auto& notification : m_pop_notifications) { | ||||
| 					//if (notification->get_state() != PopNotification::EState::Static)
 | ||||
| 						notification->substract_remaining_time(MAX_TIMEOUT_SECONDS); | ||||
| 				} | ||||
| 				m_last_time = now; | ||||
| 			} | ||||
| 		} | ||||
| 	} | ||||
| 	*/ | ||||
| } | ||||
| 
 | ||||
| bool NotificationManager::has_slicing_error_notification() | ||||
| { | ||||
| 	return std::any_of(m_pop_notifications.begin(), m_pop_notifications.end(), [](auto &n) { | ||||
|  |  | |||
|  | @ -147,14 +147,15 @@ public: | |||
| 	// finds ExportFinished notification and closes it if it was to removable device
 | ||||
| 	void device_ejected(); | ||||
| 	// renders notifications in queue and deletes expired ones
 | ||||
| 	void render_notifications(float overlay_width); | ||||
| 	void render_notifications(GLCanvas3D& canvas, float overlay_width); | ||||
| 	// finds and closes all notifications of given type
 | ||||
| 	void close_notification_of_type(const NotificationType type); | ||||
| 	// Which view is active? Plater or G-code preview? Hide warnings in G-code preview.
 | ||||
|     void set_in_preview(bool preview); | ||||
| 	// Move to left to avoid colision with variable layer height gizmo.
 | ||||
| 	void set_move_from_overlay(bool move) { m_move_from_overlay = move; } | ||||
| 
 | ||||
| 	// perform update_state on each notification and ask for more frames if needed, return true for render needed
 | ||||
| 	bool update_notifications(GLCanvas3D& canvas); | ||||
| private: | ||||
| 	// duration 0 means not disapearing
 | ||||
| 	struct NotificationData { | ||||
|  | @ -192,23 +193,24 @@ private: | |||
| 
 | ||||
| 		enum class EState | ||||
| 		{ | ||||
| 			Unknown, | ||||
| 			Unknown,		  // NOT initialized
 | ||||
| 			Hidden, | ||||
| 			FadingOutRender,  // Requesting Render
 | ||||
| 			FadingOutStatic, | ||||
| 			Shown,			  // Requesting Render at some time if duration != 0
 | ||||
| 			FadingOut,        // Requesting Render at some time
 | ||||
| 			ClosePending,     // Requesting Render
 | ||||
| 			Finished,         // Requesting Render
 | ||||
| 			Hovered,		  // Followed by Shown 
 | ||||
| 			Paused | ||||
| 		}; | ||||
| 
 | ||||
| 		PopNotification(const NotificationData &n, NotificationIDProvider &id_provider, wxEvtHandler* evt_handler); | ||||
| 		virtual ~PopNotification() { if (m_id) m_id_provider.release_id(m_id); } | ||||
| 		void                   render(GLCanvas3D& canvas, float initial_y, bool move_from_overlay, float overlay_width); | ||||
| 		// close will dissapear notification on next render
 | ||||
| 		void                   close() { m_close_pending = true; } | ||||
| 		virtual void           close() { m_state = EState::ClosePending; } | ||||
| 		// data from newer notification of same type
 | ||||
| 		void                   update(const NotificationData& n); | ||||
| 		bool                   is_finished() const { return m_finished || m_close_pending; } | ||||
| 		bool                   is_hovered() const { return m_hovered; } | ||||
| 		bool                   is_finished() const { return m_state == EState::ClosePending || m_state == EState::Finished; } | ||||
| 		// returns top after movement
 | ||||
| 		float                  get_top() const { return m_top_y; } | ||||
| 		//returns top in actual frame
 | ||||
|  | @ -216,21 +218,15 @@ private: | |||
| 		const NotificationType get_type() const { return m_data.type; } | ||||
| 		const NotificationData get_data() const { return m_data; } | ||||
| 		const bool             is_gray() const { return m_is_gray; } | ||||
| 		// Call equals one second down
 | ||||
| 		void                   substract_remaining_time(int seconds) { m_remaining_time -= seconds; } | ||||
| 		void                   set_gray(bool g) { m_is_gray = g; } | ||||
| 		void                   set_paused(bool p) { m_paused = p; } | ||||
| 		bool                   compare_text(const std::string& text); | ||||
|         void                   hide(bool h) { m_hidden = h; } | ||||
| 		// sets m_next_render with time of next mandatory rendering
 | ||||
| 		void                   update_state(); | ||||
| 		int64_t 		       next_render() const { return m_next_render; } | ||||
| 		/*
 | ||||
| 		bool				   requires_render() const { return m_state == EState::FadingOutRender || m_state == EState::ClosePending || m_state == EState::Finished; } | ||||
| 		bool				   requires_update() const { return m_state != EState::Hidden; } | ||||
| 		*/ | ||||
| 		EState                 get_state() const { return m_state; } | ||||
| 	protected: | ||||
|         void                   hide(bool h) {  m_state = h ? EState::Hidden : EState::Unknown; } | ||||
| 		// sets m_next_render with time of next mandatory rendering. Delta is time since last render.
 | ||||
| 		void                   update_state(bool paused, const int64_t delta); | ||||
| 		int64_t 		       next_render() const { return is_finished() ? 0 : m_next_render; } | ||||
| 		EState                 get_state()  const { return m_state; } | ||||
| 		bool				   is_hovered() const { return m_state == EState::Hovered; }  | ||||
| 	 | ||||
| 		// Call after every size change
 | ||||
| 		void         init(); | ||||
| 		// Part of init() 
 | ||||
|  | @ -254,45 +250,36 @@ private: | |||
| 		// Hypertext action, returns true if notification should close.
 | ||||
| 		// Action is stored in NotificationData::callback as std::function<bool(wxEvtHandler*)>
 | ||||
| 		virtual bool on_text_click(); | ||||
| 
 | ||||
| 	protected: | ||||
| 		const NotificationData m_data; | ||||
| 
 | ||||
| 		// For reusing ImGUI windows.
 | ||||
| 		NotificationIDProvider &m_id_provider; | ||||
| 		int              m_id{ 0 }; | ||||
| 
 | ||||
| 		// State for rendering
 | ||||
| 		EState           m_state                { EState::Unknown }; | ||||
| 
 | ||||
| 		int              m_id                   { 0 }; | ||||
| 		bool			 m_initialized          { false }; | ||||
| 		// Time values for rendering fade-out
 | ||||
| 
 | ||||
| 		int64_t		 	 m_fading_start{ 0LL }; | ||||
| 
 | ||||
| 		// first appereance of notification or last hover;
 | ||||
| 		int64_t		 	 m_notification_start; | ||||
| 		// time to next must-do render
 | ||||
| 		int64_t          m_next_render{ std::numeric_limits<int64_t>::max() }; | ||||
| 		float            m_current_fade_opacity{ 1.0f }; | ||||
| 
 | ||||
| 		// Notification data
 | ||||
| 
 | ||||
| 		// Main text
 | ||||
| 		std::string      m_text1; | ||||
| 		// Clickable text
 | ||||
| 		std::string      m_hypertext; | ||||
| 		// Aditional text after hypertext - currently not used
 | ||||
| 		std::string      m_text2; | ||||
| 		// Countdown variables
 | ||||
| 		long             m_remaining_time; | ||||
| 		bool             m_counting_down; | ||||
| 		long             m_last_remaining_time; | ||||
| 		bool             m_paused               { false }; | ||||
| 		int              m_countdown_frame      { 0 }; | ||||
| 		bool             m_fading_out           { false }; | ||||
| 		int64_t		 	 m_fading_start         { 0LL }; | ||||
| 		// time of last done render when fading
 | ||||
| 		int64_t		 	 m_last_render_fading   { 0LL }; | ||||
| 		// first appereance of notification or last hover;
 | ||||
| 		int64_t		 	 m_notification_start; | ||||
| 		// time to next must-do render
 | ||||
| 		int64_t          m_next_render          { std::numeric_limits<int64_t>::max() }; | ||||
| 		float            m_current_fade_opacity { 1.0f }; | ||||
| 		// If hidden the notif is alive but not visible to user
 | ||||
| 		bool             m_hidden               { false }; | ||||
| 		//  m_finished = true - does not render, marked to delete
 | ||||
| 		bool             m_finished             { false };  | ||||
| 		// Will go to m_finished next render
 | ||||
| 		bool             m_close_pending        { false }; | ||||
| 		bool             m_hovered              { false }; | ||||
| 		// variables to count positions correctly
 | ||||
| 
 | ||||
| 		// inner variables to position notification window, texts and buttons correctly
 | ||||
| 
 | ||||
| 		// all space without text
 | ||||
| 		float            m_window_width_offset; | ||||
| 		// Space on left side without text
 | ||||
|  | @ -302,9 +289,7 @@ private: | |||
| 		float            m_window_width         { 450.0f }; | ||||
| 		//Distance from bottom of notifications to top of this notification
 | ||||
| 		float            m_top_y                { 0.0f };   | ||||
| 		 | ||||
| 		// Height of text
 | ||||
| 		// Used as basic scaling unit!
 | ||||
| 		// Height of text - Used as basic scaling unit!
 | ||||
| 		float            m_line_height; | ||||
|         std::vector<size_t> m_endlines; | ||||
| 		// Gray are f.e. eorrors when its uknown if they are still valid
 | ||||
|  | @ -344,6 +329,15 @@ private: | |||
| 		int    		warning_step; | ||||
| 	}; | ||||
| 
 | ||||
| 	class PlaterWarningNotification : public PopNotification | ||||
| 	{ | ||||
| 	public: | ||||
| 		PlaterWarningNotification(const NotificationData& n, NotificationIDProvider& id_provider, wxEvtHandler* evt_handler) : PopNotification(n, id_provider, evt_handler) {} | ||||
| 		virtual void close()      { m_state = EState::Hidden; } | ||||
| 		void		 real_close() { m_state = EState::ClosePending; } | ||||
| 		void         show()       { m_state = EState::Unknown; } | ||||
| 	}; | ||||
| 
 | ||||
| 	class ProgressBarNotification : public PopNotification | ||||
| 	{ | ||||
| 	public: | ||||
|  | @ -405,33 +399,25 @@ private: | |||
| 	void sort_notifications(); | ||||
| 	// If there is some error notification active, then the "Export G-code" notification after the slicing is finished is suppressed.
 | ||||
|     bool has_slicing_error_notification(); | ||||
| 	// perform update_state on each notification and ask for more frames if needed
 | ||||
| 	void update_notifications(); | ||||
| 
 | ||||
|      | ||||
| 	// Target for wxWidgets events sent by clicking on the hyperlink available at some notifications.
 | ||||
| 	wxEvtHandler*                m_evt_handler; | ||||
| 	// Cache of IDs to identify and reuse ImGUI windows.
 | ||||
| 	NotificationIDProvider 		 m_id_provider; | ||||
| 	std::deque<std::unique_ptr<PopNotification>> m_pop_notifications; | ||||
| 	// Last render time in seconds for fade out control.
 | ||||
| 	long                         m_last_time { 0 }; | ||||
| 	// When mouse hovers over some notification, the fade-out of all notifications is suppressed.
 | ||||
| 	bool                         m_hovered { false }; | ||||
| 	//timestamps used for slicing finished - notification could be gone so it needs to be stored here
 | ||||
| 	std::unordered_set<int>      m_used_timestamps; | ||||
| 	// True if G-code preview is active. False if the Plater is active.
 | ||||
| 	bool                         m_in_preview { false }; | ||||
| 	// True if the layer editing is enabled in Plater, so that the notifications are shifted left of it.
 | ||||
| 	bool                         m_move_from_overlay { false }; | ||||
| 	// Timestamp of last rendering
 | ||||
| 	int64_t						 m_last_render { 0LL }; | ||||
| 
 | ||||
| 	//prepared (basic) notifications
 | ||||
| 	const std::vector<NotificationData> basic_notifications = { | ||||
| //		{NotificationType::SlicingNotPossible, NotificationLevel::RegularNotification, 10,  _u8L("Slicing is not possible.")},
 | ||||
| //		{NotificationType::ExportToRemovableFinished, NotificationLevel::ImportantNotification, 0,  _u8L("Exporting finished."),  _u8L("Eject drive.") },
 | ||||
| 		{NotificationType::Mouse3dDisconnected, NotificationLevel::RegularNotification, 10,  _u8L("3D Mouse disconnected.") }, | ||||
| //		{NotificationType::Mouse3dConnected, NotificationLevel::RegularNotification, 5,  _u8L("3D Mouse connected.") },
 | ||||
| //		{NotificationType::NewPresetsAviable, NotificationLevel::ImportantNotification, 20,  _u8L("New Presets are available."),  _u8L("See here.") },
 | ||||
|         {NotificationType::PresetUpdateAvailable, NotificationLevel::ImportantNotification, 20,  _u8L("Configuration update is available."),  _u8L("See more."), | ||||
|         {NotificationType::PresetUpdateAvailable, NotificationLevel::ImportantNotification, 10,  _u8L("Configuration update is available."),  _u8L("See more."), | ||||
|              [](wxEvtHandler* evnthndlr) { | ||||
|                  if (evnthndlr != nullptr) | ||||
|                      wxPostEvent(evnthndlr, PresetUpdateAvailableClickedEvent(EVT_PRESET_UPDATE_AVAILABLE_CLICKED)); | ||||
|  |  | |||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue
	
	 David Kocik
						David Kocik