diff --git a/src/slic3r/GUI/Camera.hpp b/src/slic3r/GUI/Camera.hpp index 2a84b4156..6eb44a927 100644 --- a/src/slic3r/GUI/Camera.hpp +++ b/src/slic3r/GUI/Camera.hpp @@ -139,7 +139,7 @@ public: // returns true if the camera z axis (forward) is pointing in the negative direction of the world z axis bool is_looking_downward() const { return get_dir_forward().dot(Vec3d::UnitZ()) < 0.0; } - + bool is_looking_front() const { return abs(get_dir_up().dot(Vec3d::UnitZ())-1) < 0.001; } // forces camera right vector to be parallel to XY plane void recover_from_free_camera() { if (std::abs(get_dir_right()(2)) > EPSILON) diff --git a/src/slic3r/GUI/Gizmos/GLGizmoAdvancedCut.hpp b/src/slic3r/GUI/Gizmos/GLGizmoAdvancedCut.hpp index f18754067..18b5b4d64 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoAdvancedCut.hpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoAdvancedCut.hpp @@ -334,11 +334,6 @@ private: bool render_combo(const std::string &label, const std::vector &lines, size_t &selection_idx, float label_width, float item_width); bool render_slider_double_input(const std::string &label, float &value_in, float &tolerance_in); - enum DoubleShowType { - Normal, // origin data - PERCENTAGE, - DEGREE, - }; bool render_slider_double_input_by_format(const std::string &label, float &value_in, float value_min, float value_max, DoubleShowType show_type = DoubleShowType::Normal); bool cut_line_processing() const; void discard_cut_line_processing(); diff --git a/src/slic3r/GUI/Gizmos/GLGizmoBase.cpp b/src/slic3r/GUI/Gizmos/GLGizmoBase.cpp index 4e6553c25..37877f63e 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoBase.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoBase.cpp @@ -145,7 +145,52 @@ void GLGizmoBase::Grabber::render(float size, const std::array& render } -GLGizmoBase::GLGizmoBase(GLCanvas3D& parent, const std::string& icon_filename, unsigned int sprite_id) +bool GLGizmoBase::render_slider_double_input_by_format( + const SliderInputLayout &layout, const std::string &label, float &value_in, float value_min, float value_max, int keep_digit, DoubleShowType show_type) +{ + ImGui::AlignTextToFramePadding(); + m_imgui->text(label); + ImGui::SameLine(layout.sliders_left_width); + ImGui::PushItemWidth(layout.sliders_width); + + float old_val = value_in; // (show_type == DoubleShowType::Normal) + float value = value_in; // (show_type == DoubleShowType::Normal) + std::string format = "%." + std::to_string(keep_digit) + "f"; + if (show_type == DoubleShowType::PERCENTAGE) { + format = "%." + std::to_string(keep_digit) + "f %%"; + old_val = value_in; + value = value_in * 100; + } else if (show_type == DoubleShowType::DEGREE) { + format = "%." + std::to_string(keep_digit) + "f " + _u8L("°"); + old_val = value_in; + value = Geometry::rad2deg(value_in); + } + + if (m_imgui->bbl_slider_float_style(("##" + label).c_str(), &value, value_min, value_max, format.c_str())) { + if (show_type == DoubleShowType::PERCENTAGE) { + value_in = value * 0.01f; + } else if (show_type == DoubleShowType::DEGREE) { + value_in = Geometry::deg2rad(value); + } else { //(show_type == DoubleShowType::Normal) + value_in = value; + } + } + + ImGui::SameLine(layout.input_left_width); + ImGui::PushItemWidth(layout.input_width); + if (ImGui::BBLDragFloat(("##input_" + label).c_str(), &value, 0.05f, value_min, value_max, format.c_str())) { + if (show_type == DoubleShowType::PERCENTAGE) { + value_in = value * 0.01f; + } else if (show_type == DoubleShowType::DEGREE) { + value_in = Geometry::deg2rad(value); + } else { //(show_type == DoubleShowType::Normal) + value_in = value; + } + } + return !is_approx(old_val, value_in); +} + +GLGizmoBase::GLGizmoBase(GLCanvas3D &parent, const std::string &icon_filename, unsigned int sprite_id) : m_parent(parent) , m_group_id(-1) , m_state(Off) diff --git a/src/slic3r/GUI/Gizmos/GLGizmoBase.hpp b/src/slic3r/GUI/Gizmos/GLGizmoBase.hpp index 6117e931c..786580059 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoBase.hpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoBase.hpp @@ -129,6 +129,25 @@ protected: bool m_is_dark_mode = false; std::chrono::system_clock::time_point start; + enum DoubleShowType { + Normal, // origin data + PERCENTAGE, + DEGREE,//input must is radian + }; + struct SliderInputLayout + { + float sliders_left_width; + float sliders_width; + float input_left_width; + float input_width; + }; + bool render_slider_double_input_by_format(const SliderInputLayout & layout, + const std::string & label, + float & value_in, + float value_min, + float value_max, + int keep_digit , + DoubleShowType show_type = DoubleShowType::Normal); public: GLGizmoBase(GLCanvas3D& parent, diff --git a/src/slic3r/GUI/Gizmos/GLGizmoMmuSegmentation.cpp b/src/slic3r/GUI/Gizmos/GLGizmoMmuSegmentation.cpp index 13c27ef5a..d76f50845 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoMmuSegmentation.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoMmuSegmentation.cpp @@ -393,8 +393,11 @@ void GLGizmoMmuSegmentation::on_render_input_window(float x, float y, float bott // First calculate width of all the texts that are could possibly be shown. We will decide set the dialog width based on that: const float space_size = m_imgui->get_style_scaling() * 8; - const float clipping_slider_left = std::max(m_imgui->calc_text_size(m_desc.at("clipping_of_view")).x + m_imgui->scaled(1.5f), + float clipping_slider_left = std::max(m_imgui->calc_text_size(m_desc.at("clipping_of_view")).x + m_imgui->scaled(1.5f), m_imgui->calc_text_size(m_desc.at("reset_direction")).x + m_imgui->scaled(1.5f) + ImGui::GetStyle().FramePadding.x * 2); + float rotate_horizontal_text= m_imgui->calc_text_size(_L("Rotate horizontally")).x + m_imgui->scaled(1.5f); + clipping_slider_left = std::max(rotate_horizontal_text, clipping_slider_left); + const float cursor_slider_left = m_imgui->calc_text_size(m_desc.at("cursor_size")).x + m_imgui->scaled(1.5f); const float smart_fill_slider_left = m_imgui->calc_text_size(m_desc.at("smart_fill_angle")).x + m_imgui->scaled(1.5f); const float edge_detect_slider_left = m_imgui->calc_text_size(m_desc.at("edge_detection")).x + m_imgui->scaled(1.f); @@ -442,6 +445,9 @@ void GLGizmoMmuSegmentation::on_render_input_window(float x, float y, float bott float color_button = ImGui::GetCursorPos().y; + float textbox_width = 1.5 * slider_icon_width; + SliderInputLayout slider_input_layout = {clipping_slider_left, sliders_width, drag_left_width + circle_max_width, textbox_width}; + m_imgui->text(m_desc.at("filaments")); float start_pos_x = ImGui::GetCursorPos().x; @@ -712,17 +718,49 @@ void GLGizmoMmuSegmentation::on_render_input_window(float x, float y, float bott ImGui::BBLDragFloat("##gap_area_input", &TriangleSelectorPatch::gap_area, 0.05f, 0.0f, 0.0f, "%.2f"); } ImGui::Separator(); - if (m_imgui->bbl_checkbox(_L("Vertical"), m_vertical_only)) { - if (m_vertical_only) { - m_horizontal_only = false; + if (m_current_tool == ImGui::CircleButtonIcon || m_current_tool == ImGui::SphereButtonIcon) { + float vertical_text_width = m_imgui->calc_button_size(_L("Vertical")).x; + float horizontal_text_width = m_imgui->calc_button_size(_L("Horizontal")).x; + if (!wxGetApp().plater()->get_camera().is_looking_front()) { + m_is_front_view = false; } - } - if (m_imgui->bbl_checkbox(_L("Horizontal"), m_horizontal_only)) { - if (m_horizontal_only) { - m_vertical_only = false; + auto vertical_only = m_vertical_only; + if (m_imgui->bbl_checkbox(_L("Vertical"), vertical_only)) { + m_vertical_only = vertical_only; + if (m_vertical_only) { + m_horizontal_only = false; + m_is_front_view = true; + change_camera_view_angle(m_front_view_radian); + } } - } + ImGui::SameLine(vertical_text_width * 2.0); + ImGui::PushItemWidth(horizontal_text_width * 2.0); + auto horizontal_only = m_horizontal_only; + if (m_imgui->bbl_checkbox(_L("Horizontal"), horizontal_only)) { + m_horizontal_only = horizontal_only; + if (m_horizontal_only) { + m_vertical_only = false; + m_is_front_view = true; + change_camera_view_angle(m_front_view_radian); + } + } + + auto is_front_view = m_is_front_view; + m_imgui->bbl_checkbox(_L("View: keep horizontal"), is_front_view); + if (m_is_front_view != is_front_view) { + m_is_front_view = is_front_view; + if (m_is_front_view) { + change_camera_view_angle(m_front_view_radian); + } + } + m_imgui->disabled_begin(!m_is_front_view); + + if (render_slider_double_input_by_format(slider_input_layout, _u8L("Rotate horizontally"), m_front_view_radian, 0.f, 360.f, 0, DoubleShowType::DEGREE)) { + change_camera_view_angle(m_front_view_radian); + } + m_imgui->disabled_end(); + } ImGui::Separator(); ImGui::PushStyleVar(ImGuiStyleVar_ItemSpacing, ImVec2(6.0f, 10.0f)); float get_cur_y = ImGui::GetContentRegionMax().y + ImGui::GetFrameHeight() + y; diff --git a/src/slic3r/GUI/Gizmos/GLGizmoPainterBase.cpp b/src/slic3r/GUI/Gizmos/GLGizmoPainterBase.cpp index 8f0dfa3a9..369143774 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoPainterBase.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoPainterBase.cpp @@ -28,8 +28,6 @@ GLGizmoPainterBase::GLGizmoPainterBase(GLCanvas3D& parent, const std::string& ic // Make sphere and save it into a vertex buffer. m_vbo_sphere.load_its_flat_shading(its_make_sphere(1., (2*M_PI)/24.)); m_vbo_sphere.finalize_geometry(true); - m_vertical_only = false; - m_horizontal_only = false; } void GLGizmoPainterBase::set_painter_gizmo_data(const Selection& selection) @@ -1094,6 +1092,10 @@ void GLGizmoPainterBase::on_set_state() //camera.recover_from_free_camera(); } m_old_state = m_state; + m_vertical_only = false; + m_horizontal_only = false; + m_is_front_view = false; + m_front_view_radian = 0; } @@ -1127,6 +1129,14 @@ TriangleSelector::ClippingPlane GLGizmoPainterBase::get_clipping_plane_in_volume return TriangleSelector::ClippingPlane({float(normal_transformed.x()), float(normal_transformed.y()), float(normal_transformed.z()), offset_transformed}); } +void GLGizmoPainterBase::change_camera_view_angle(float front_view_radian) +{ + wxGetApp().plater()->get_camera().select_view("front"); + const Selection &selection = m_parent.get_selection(); + auto rotate_target = selection.get_bounding_box().center(); + wxGetApp().plater()->get_camera().rotate_local_with_target(Vec3d(0, front_view_radian, 0), rotate_target); +} + std::array TriangleSelectorGUI::get_seed_fill_color(const std::array &base_color) { // BBS diff --git a/src/slic3r/GUI/Gizmos/GLGizmoPainterBase.hpp b/src/slic3r/GUI/Gizmos/GLGizmoPainterBase.hpp index ff1297b4e..a3d6d365e 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoPainterBase.hpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoPainterBase.hpp @@ -305,9 +305,10 @@ protected: static constexpr float SmartFillAngleStep = 1.f; // BBL: paint behavior enchancement - bool m_vertical_only = false; - bool m_horizontal_only = false; - + bool m_vertical_only = false; + bool m_horizontal_only = false; + bool m_is_front_view = false; + float m_front_view_radian = 0; // It stores the value of the previous mesh_id to which the seed fill was applied. // It is used to detect when the mouse has moved from one volume to another one. int m_seed_fill_last_mesh_id = -1; @@ -328,7 +329,8 @@ protected: TriangleSelector::ClippingPlane get_clipping_plane_in_volume_coordinates(const Transform3d &trafo) const; -private: + void change_camera_view_angle(float front_view_radian); + private: std::vector> get_projected_mouse_positions(const Vec2d &mouse_position, double resolution, const std::vector &trafo_matrices) const; std::vector get_projected_height_range(const Vec2d& mouse_position, double resolution, const std::vector& part_volumes, const std::vector& trafo_matrices) const; diff --git a/src/slic3r/GUI/Gizmos/GLGizmoSeam.cpp b/src/slic3r/GUI/Gizmos/GLGizmoSeam.cpp index e28066067..c27ec0622 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoSeam.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoSeam.cpp @@ -201,9 +201,11 @@ void GLGizmoSeam::on_render_input_window(float x, float y, float bottom_limit) // First calculate width of all the texts that are could possibly be shown. We will decide set the dialog width based on that: const float space_size = m_imgui->get_style_scaling() * 8; - const float clipping_slider_left = std::max(m_imgui->calc_text_size(m_desc.at("clipping_of_view")).x, - m_imgui->calc_text_size(m_desc.at("reset_direction")).x + ImGui::GetStyle().FramePadding.x * 2) - + m_imgui->scaled(1.5f); + float clipping_slider_left = std::max(m_imgui->calc_text_size(m_desc.at("clipping_of_view")).x, + m_imgui->calc_text_size(m_desc.at("reset_direction")).x + ImGui::GetStyle().FramePadding.x * 2) + + m_imgui->scaled(1.5f); + float rotate_horizontal_text = m_imgui->calc_text_size(_L("Rotate horizontally")).x + m_imgui->scaled(1.5f); + clipping_slider_left = std::max(rotate_horizontal_text, clipping_slider_left); const float cursor_size_slider_left = m_imgui->calc_text_size(m_desc.at("cursor_size")).x + m_imgui->scaled(1.f); const float empty_button_width = m_imgui->calc_button_size("").x; @@ -222,6 +224,9 @@ void GLGizmoSeam::on_render_input_window(float x, float y, float bottom_limit) const float max_tooltip_width = ImGui::GetFontSize() * 20.0f; + float textbox_width = 1.5 * slider_icon_width; + SliderInputLayout slider_input_layout = {sliders_left_width, sliders_width, drag_left_width, textbox_width}; + ImGui::AlignTextToFramePadding(); m_imgui->text(m_desc.at("cursor_type")); std::array tool_ids = { ImGui::CircleButtonIcon, ImGui::SphereButtonIcon }; @@ -313,8 +318,31 @@ void GLGizmoSeam::on_render_input_window(float x, float y, float bottom_limit) if (slider_clp_dist || b_clp_dist_input) { m_c->object_clipper()->set_position(clp_dist, true); } ImGui::Separator(); - m_imgui->bbl_checkbox(_L("Vertical"), m_vertical_only); + if (!wxGetApp().plater()->get_camera().is_looking_front()){ + m_is_front_view = false; + } + auto vertical_only = m_vertical_only; + if (m_imgui->bbl_checkbox(_L("Vertical"), vertical_only)) { + m_vertical_only = vertical_only; + if (m_vertical_only) { + m_is_front_view = true; + change_camera_view_angle(m_front_view_radian); + } + } + auto is_front_view = m_is_front_view; + m_imgui->bbl_checkbox(_L("View: keep horizontal"), is_front_view); + if (m_is_front_view != is_front_view) { + m_is_front_view = is_front_view; + if (m_is_front_view) { + change_camera_view_angle(m_front_view_radian); + } + } + m_imgui->disabled_begin(!m_is_front_view); + if (render_slider_double_input_by_format(slider_input_layout, _u8L("Rotate horizontally"), m_front_view_radian, 0.f, 360.f, 0, DoubleShowType::DEGREE)) { + change_camera_view_angle(m_front_view_radian); + } + m_imgui->disabled_end(); ImGui::Separator(); ImGui::PushStyleVar(ImGuiStyleVar_ItemSpacing, ImVec2(6.0f, 10.0f)); float get_cur_y = ImGui::GetContentRegionMax().y + ImGui::GetFrameHeight() + y;