diff --git a/src/slic3r/GUI/GLCanvas3D.cpp b/src/slic3r/GUI/GLCanvas3D.cpp index aef3cb4dc..5f47419a1 100644 --- a/src/slic3r/GUI/GLCanvas3D.cpp +++ b/src/slic3r/GUI/GLCanvas3D.cpp @@ -5464,6 +5464,14 @@ bool GLCanvas3D::is_object_sinking(int object_idx) const return false; } +void GLCanvas3D::apply_retina_scale(Vec2d &screen_coordinate) const +{ +#if ENABLE_RETINA_GL + double scale = static_cast(m_retina_helper->get_scale_factor()); + screen_coordinate *= scale; +#endif // ENABLE_RETINA_GL} +} + bool GLCanvas3D::_is_shown_on_screen() const { return (m_canvas != nullptr) ? m_canvas->IsShownOnScreen() : false; diff --git a/src/slic3r/GUI/GLCanvas3D.hpp b/src/slic3r/GUI/GLCanvas3D.hpp index 2c5fab31d..680b0001e 100644 --- a/src/slic3r/GUI/GLCanvas3D.hpp +++ b/src/slic3r/GUI/GLCanvas3D.hpp @@ -949,6 +949,12 @@ public: Size get_canvas_size() const; Vec2d get_local_mouse_position() const; + // store opening position of menu + std::optional m_popup_menu_positon; // position of mouse right click + void set_popup_menu_position(const Vec2d &position) { m_popup_menu_positon = position; } + const std::optional &get_popup_menu_position() const { return m_popup_menu_positon; } + void clear_popup_menu_position() { m_popup_menu_positon.reset(); } + void set_tooltip(const std::string& tooltip); // the following methods add a snapshot to the undo/redo stack, unless the given string is empty @@ -1080,7 +1086,7 @@ public: void reset_old_size() { m_old_size = { 0, 0 }; } bool is_object_sinking(int object_idx) const; - + void apply_retina_scale(Vec2d &screen_coordinate) const; void _perform_layer_editing_action(wxMouseEvent* evt = nullptr); // Convert the screen space coordinate to an object space coordinate. diff --git a/src/slic3r/GUI/GUI_Factories.cpp b/src/slic3r/GUI/GUI_Factories.cpp index 0c3161a29..2292e3fc5 100644 --- a/src/slic3r/GUI/GUI_Factories.cpp +++ b/src/slic3r/GUI/GUI_Factories.cpp @@ -16,6 +16,8 @@ //BBS: add partplate related logic #include "PartPlate.hpp" +#include "Gizmos/GLGizmoSVG.hpp" + #include #include "slic3r/Utils/FixModelByWin10.hpp" #include "ParamsPanel.hpp" @@ -436,10 +438,8 @@ std::vector MenuFactory::get_volume_bitmaps() { std::vector volume_bmps; volume_bmps.reserve(ADD_VOLUME_MENU_ITEMS.size()); - for (auto item : ADD_VOLUME_MENU_ITEMS){ - if(!item.second.empty()){ - volume_bmps.push_back(create_scaled_bitmap(item.second)); - } + for (const auto &item : ADD_VOLUME_MENU_ITEMS) { + volume_bmps.push_back(create_scaled_bitmap(item.second)); } return volume_bmps; } @@ -486,6 +486,7 @@ void MenuFactory::append_menu_item_delete(wxMenu* menu) #endif } + void MenuFactory::append_menu_item_edit_text(wxMenu *menu) { #ifdef __WINDOWS__ @@ -553,10 +554,60 @@ wxMenu* MenuFactory::append_submenu_add_generic(wxMenu* menu, ModelVolumeType ty sub_menu, wxID_ANY, _(item), "", [type, item](wxCommandEvent &) { obj_list()->load_generic_subobject(item, type); }, "", menu); } } - + append_menu_item_add_svg(sub_menu, type); return sub_menu; } +static void append_menu_itemm_add_(const wxString &name, GLGizmosManager::EType gizmo_type, wxMenu *menu, ModelVolumeType type, bool is_submenu_item) +{ + auto add_ = [type, gizmo_type](const wxCommandEvent & /*unnamed*/) { + const GLCanvas3D * canvas = plater()->canvas3D(); + const GLGizmosManager &mng = canvas->get_gizmos_manager(); + GLGizmoBase * gizmo_base = mng.get_gizmo(gizmo_type); + + ModelVolumeType volume_type = type; + // no selected object means create new object + if (volume_type == ModelVolumeType::INVALID) + volume_type = ModelVolumeType::MODEL_PART; + + auto screen_position = canvas->get_popup_menu_position(); + /* if (gizmo_type == GLGizmosManager::Emboss) {//todo + auto emboss = dynamic_cast(gizmo_base); + assert(emboss != nullptr); + if (emboss == nullptr) return; + if (screen_position.has_value()) { + emboss->create_volume(volume_type, *screen_position); + } else { + emboss->create_volume(volume_type); + } + } else*/ if (gizmo_type == GLGizmosManager::Svg) { + auto svg = dynamic_cast(gizmo_base); + assert(svg != nullptr); + if (svg == nullptr) return; + if (screen_position.has_value()) { + svg->create_volume(volume_type, *screen_position); + } else { + svg->create_volume(volume_type); + } + } + }; + + if (type == ModelVolumeType::MODEL_PART || type == ModelVolumeType::NEGATIVE_VOLUME || type == ModelVolumeType::PARAMETER_MODIFIER || + type == ModelVolumeType::INVALID // cannot use gizmo without selected object + ) { + wxString item_name = wxString(is_submenu_item ? "" : _(ADD_VOLUME_MENU_ITEMS[int(type)].first) + ": ") + name; + menu->AppendSeparator(); + auto def_icon_name = (gizmo_type == GLGizmosManager::Svg) ? "menu_obj_svg" : "menu_obj_text"; + const std::string icon_name = is_submenu_item ? def_icon_name : ADD_VOLUME_MENU_ITEMS[int(type)].second; + append_menu_item(menu, wxID_ANY, item_name, "", add_, icon_name, menu); + } +} + +void MenuFactory::append_menu_item_add_svg(wxMenu *menu, ModelVolumeType type, bool is_submenu_item /* = true*/) +{ + append_menu_itemm_add_(_L("SVG"), GLGizmosManager::Svg, menu, type, is_submenu_item); +} + void MenuFactory::append_menu_items_add_volume(wxMenu* menu) { // Update "add" items(delete old & create new) settings popupmenu diff --git a/src/slic3r/GUI/GUI_Factories.hpp b/src/slic3r/GUI/GUI_Factories.hpp index 5a82f6f15..a54e4bc79 100644 --- a/src/slic3r/GUI/GUI_Factories.hpp +++ b/src/slic3r/GUI/GUI_Factories.hpp @@ -128,6 +128,7 @@ private: void create_bbl_assemble_part_menu(); wxMenu* append_submenu_add_generic(wxMenu* menu, ModelVolumeType type); + void append_menu_item_add_svg(wxMenu *menu, ModelVolumeType type, bool is_submenu_item = true); void append_menu_items_add_volume(wxMenu* menu); wxMenuItem* append_menu_item_layers_editing(wxMenu* menu); wxMenuItem* append_menu_item_settings(wxMenu* menu); diff --git a/src/slic3r/GUI/Gizmos/GLGizmoSVG.cpp b/src/slic3r/GUI/Gizmos/GLGizmoSVG.cpp index f6d6bf200..78bf78793 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoSVG.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoSVG.cpp @@ -424,6 +424,24 @@ bool reset_button(const IconManager::VIcons &icons) return draw_clickable(icons, IconType::reset_value); } +bool GLGizmoSVG::create_volume(ModelVolumeType volume_type) +{ + Emboss::CreateVolumeParams input = create_input(m_parent, volume_type); + Emboss::DataBasePtr base = create_emboss_data_base(m_job_cancel, volume_type); + if (!base) + return false; // Uninterpretable svg + return start_create_volume_without_position(input, std::move(base)); +} + +bool GLGizmoSVG::create_volume(ModelVolumeType volume_type, const Vec2d &mouse_pos) +{ + Emboss::CreateVolumeParams input = create_input(m_parent, volume_type); + Emboss::DataBasePtr base = create_emboss_data_base(m_job_cancel, volume_type); + if (!base) + return false; // Uninterpretable svg + return start_create_volume(input, std::move(base), mouse_pos); +} + bool GLGizmoSVG::create_volume(std::string_view svg_file, const Vec2d &mouse_pos, ModelVolumeType volume_type) {//drag file//drag svg_file wxBusyCursor wait; diff --git a/src/slic3r/GUI/Gizmos/GLGizmoSVG.hpp b/src/slic3r/GUI/Gizmos/GLGizmoSVG.hpp index 945791d97..7f344a1a3 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoSVG.hpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoSVG.hpp @@ -22,7 +22,7 @@ class Worker; enum class SLAGizmoEventType : unsigned char; class GLGizmoSVG : public GLGizmoBase { - Emboss::DataBasePtr create_emboss_data_base(std::shared_ptr> &cancel, ModelVolumeType volume_type, std::string_view filepath); + Emboss::DataBasePtr create_emboss_data_base(std::shared_ptr> &cancel, ModelVolumeType volume_type, std::string_view filepath = ""); Emboss::CreateVolumeParams create_input(GLCanvas3D &canvas, ModelVolumeType volume_type); @@ -36,6 +36,14 @@ public: void on_enable_grabber(unsigned int id) override; void on_disable_grabber(unsigned int id) override; + /// + /// Create new text without given position + /// + /// Object part / Negative volume / Modifier + /// True on succesfull start creation otherwise False + bool create_volume(ModelVolumeType volume_type); // first open file dialog //by rigth menu + bool create_volume(ModelVolumeType volume_type, const Vec2d &mouse_pos); // first open file dialog //by rigth menu + bool create_volume(std::string_view svg_file, const Vec2d &mouse_pos, ModelVolumeType volume_type = ModelVolumeType::MODEL_PART); /// /// Check whether volume is object containing only emboss volume diff --git a/src/slic3r/GUI/Plater.cpp b/src/slic3r/GUI/Plater.cpp index 758f0f188..bbab69549 100644 --- a/src/slic3r/GUI/Plater.cpp +++ b/src/slic3r/GUI/Plater.cpp @@ -2569,6 +2569,7 @@ struct Plater::priv void on_add_custom_filament(ColorEvent &); void on_object_select(SimpleEvent&); + void show_right_click_menu(Vec2d mouse_position, wxMenu *menu); void on_plate_name_change(SimpleEvent &); void on_right_click(RBtnEvent&); //BBS: add model repair @@ -7319,6 +7320,41 @@ void Plater::priv::on_change_color_mode(SimpleEvent& evt) { if (m_send_to_sdcard_dlg) m_send_to_sdcard_dlg->on_change_color_mode(); } +static void get_position(wxWindowBase *child, wxWindowBase *until_parent, int &x, int &y) +{ + int res_x = 0, res_y = 0; + + while (child != until_parent && child != nullptr) { + int _x, _y; + child->GetPosition(&_x, &_y); + res_x += _x; + res_y += _y; + + child = child->GetParent(); + } + + x = res_x; + y = res_y; +} + +void Plater::priv::show_right_click_menu(Vec2d mouse_position, wxMenu *menu) +{ + // BBS: GUI refactor: move sidebar to the left + int x, y; + get_position(current_panel, wxGetApp().mainframe, x, y); + wxPoint position(static_cast(mouse_position.x() + x), static_cast(mouse_position.y() + y)); +#ifdef __linux__ + // For some reason on Linux the menu isn't displayed if position is + // specified (even though the position is sane). + position = wxDefaultPosition; +#endif + GLCanvas3D &canvas = *q->canvas3D(); + canvas.apply_retina_scale(mouse_position); + canvas.set_popup_menu_position(mouse_position); + q->PopupMenu(menu, position); + canvas.clear_popup_menu_position(); +} + void Plater::priv::on_right_click(RBtnEvent& evt) { int obj_idx = get_selected_object_idx(); @@ -7380,17 +7416,7 @@ void Plater::priv::on_right_click(RBtnEvent& evt) } if (q != nullptr && menu) { -#ifdef __linux__ - // For some reason on Linux the menu isn't displayed if position is specified - // (even though the position is sane). - q->PopupMenu(menu); -#else - //BBS: GUI refactor: move sidebar to the left - int x, y; - current_panel->GetPosition(&x, &y); - q->PopupMenu(menu, (int)evt.data.first.x() + x, (int)evt.data.first.y()); - //q->PopupMenu(menu); -#endif + show_right_click_menu(evt.data.first, menu); } } @@ -7398,16 +7424,7 @@ void Plater::priv::on_right_click(RBtnEvent& evt) void Plater::priv::on_plate_right_click(RBtnPlateEvent& evt) { wxMenu* menu = menus.plate_menu(); - -#ifdef __linux__ - q->PopupMenu(menu); -#else - //BBS: GUI refactor: move sidebar to the left - int x, y; - current_panel->GetPosition(&x, &y); - q->PopupMenu(menu, (int)evt.data.first.x() + x, (int)evt.data.first.y()); - //q->PopupMenu(menu); -#endif + show_right_click_menu(evt.data.first, menu); } void Plater::priv::on_update_geometry(Vec3dsEvent<2>&)