#ifndef slic3r_GLGizmoEmboss_hpp_ #define slic3r_GLGizmoEmboss_hpp_ // Include GLGizmoBase.hpp before I18N.hpp as it includes some libigl code, // which overrides our localization "L" macro. #include "GLGizmoBase.hpp" #include "GLGizmoRotate.hpp" #include "slic3r/GUI/GLTexture.hpp" #include "slic3r/Utils/RaycastManager.hpp" #include "slic3r/Utils/EmbossStyleManager.hpp" #include "admesh/stl.h" // indexed_triangle_set #include #include #include #include #include #include "libslic3r/Emboss.hpp" #include "libslic3r/Point.hpp" #include "libslic3r/Model.hpp" #include "libslic3r/TextConfiguration.hpp" #include #include class wxFont; namespace Slic3r{ class AppConfig; class GLVolume; enum class ModelVolumeType : int; } namespace Slic3r::GUI { class MeshRaycaster; class GLGizmoEmboss : public GLGizmoBase { public: GLGizmoEmboss(GLCanvas3D& parent); /// /// Create new embossed text volume by type on position of mouse /// /// Object part / Negative volume / Modifier /// Define position of new volume void create_volume(ModelVolumeType volume_type, const Vec2d &mouse_pos); /// /// Create new text without given position /// /// Object part / Negative volume / Modifier void create_volume(ModelVolumeType volume_type); protected: bool on_init() override; std::string on_get_name() const override; void on_render() override; virtual void on_register_raycasters_for_picking() override; virtual void on_unregister_raycasters_for_picking() override; void on_render_input_window(float x, float y, float bottom_limit) override; bool on_is_activable() const override { return true; } bool on_is_selectable() const override { return false; } void on_set_state() override; void on_set_hover_id() override{ m_rotate_gizmo.set_hover_id(m_hover_id); } void on_enable_grabber(unsigned int id) override { m_rotate_gizmo.enable_grabber(); } void on_disable_grabber(unsigned int id) override { m_rotate_gizmo.disable_grabber(); } void on_start_dragging() override; void on_stop_dragging() override; void on_dragging(const UpdateData &data) override; /// /// Rotate by text on dragging rotate grabers /// /// Information about mouse /// Propagete normaly return false. bool on_mouse(const wxMouseEvent &mouse_event) override; bool wants_enter_leave_snapshots() const override { return true; } std::string get_gizmo_entering_text() const override { return _u8L("Enter emboss gizmo"); } std::string get_gizmo_leaving_text() const override { return _u8L("Leave emboss gizmo"); } std::string get_action_snapshot_name() override { return _u8L("Embossing actions"); } private: void initialize(); static EmbossStyles create_default_styles(); // localized default text void set_default_text(); void set_volume_by_selection(); // load text configuration from volume into gizmo bool set_volume(ModelVolume *volume); // create volume from text - main functionality bool process(); void close(); void discard_and_close(); void draw_window(); void draw_text_input(); void draw_model_type(); void fix_transformation(const FontProp &from, const FontProp &to); void draw_style_list(); void draw_delete_style_button(); void draw_style_rename_popup(); void draw_style_rename_button(); void draw_style_save_button(bool is_modified); void draw_style_save_as_popup(); void draw_style_add_button(); void init_font_name_texture(); struct FaceName; void draw_font_preview(FaceName &face, bool is_visible); void draw_font_list(); void draw_style_edit(); void draw_height(std::optional scale, bool use_inch); void draw_depth(std::optional scale, bool use_inch); bool draw_italic_button(); bool draw_bold_button(); void draw_advanced(); bool select_facename(const wxString& facename); void init_face_names(); void do_translate(const Vec3d& relative_move); void do_rotate(float relative_z_angle); bool rev_input_mm(const std::string &name, float &value, const float *default_value, const std::string &undo_tooltip, float step, float step_fast, const char *format, bool use_inch = false, std::optional scale = {}); /// /// Reversible input float with option to restor default value /// TODO: make more general, static and move to ImGuiWrapper /// /// True when value changed otherwise FALSE. bool rev_input(const std::string &name, float &value, const float *default_value, const std::string &undo_tooltip, float step, float step_fast, const char *format, ImGuiInputTextFlags flags = 0); bool rev_checkbox(const std::string &name, bool &value, const bool* default_value, const std::string &undo_tooltip); bool rev_slider(const std::string &name, std::optional& value, const std::optional *default_value, const std::string &undo_tooltip, int v_min, int v_max, const std::string &format, const wxString &tooltip); bool rev_slider(const std::string &name, std::optional& value, const std::optional *default_value, const std::string &undo_tooltip, float v_min, float v_max, const std::string &format, const wxString &tooltip); bool rev_slider(const std::string &name, float &value, const float *default_value, const std::string &undo_tooltip, float v_min, float v_max, const std::string &format, const wxString &tooltip); template bool revertible(const std::string &name, T &value, const T *default_value, const std::string &undo_tooltip, float undo_offset, Draw draw); void set_minimal_window_size(bool is_advance_edit_style); const ImVec2 &get_minimal_window_size() const; // process mouse event bool on_mouse_for_rotation(const wxMouseEvent &mouse_event); bool on_mouse_for_translate(const wxMouseEvent &mouse_event); bool choose_font_by_wxdialog(); bool choose_true_type_file(); bool choose_svg_file(); // When open text loaded from .3mf it could be written with unknown font bool m_is_unknown_font; void create_notification_not_valid_font(const TextConfiguration& tc); void remove_notification_not_valid_font(); // This configs holds GUI layout size given by translated texts. // etc. When language changes, GUI is recreated and this class constructed again, // so the change takes effect. (info by GLGizmoFdmSupports.hpp) struct GuiCfg { // Zero means it is calculated in init function ImVec2 minimal_window_size = ImVec2(0, 0); ImVec2 minimal_window_size_with_advance = ImVec2(0, 0); ImVec2 minimal_window_size_with_collections = ImVec2(0, 0); float input_width = 0.f; float delete_pos_x = 0.f; float max_style_name_width = 0.f; unsigned int icon_width = 0; // maximal width and height of style image Vec2i max_style_image_size = Vec2i(0, 0); float style_offset = 0.f; float input_offset = 0.f; float advanced_input_offset = 0.f; ImVec2 text_size; // maximal size of face name image Vec2i face_name_size = Vec2i(100, 0); float face_name_max_width = 100.f; float face_name_texture_offset_x = 105.f; // maximal texture generate jobs running at once unsigned int max_count_opened_font_files = 10; // Only translations needed for calc GUI size struct Translations { std::string type; std::string style; std::string font; std::string size; std::string depth; std::string use_surface; // advanced std::string char_gap; std::string line_gap; std::string boldness; std::string italic; std::string surface_distance; std::string angle; std::string collection; }; Translations translations; GuiCfg() = default; }; std::optional m_gui_cfg; bool m_is_advanced_edit_style = false; // when true window will appear near to text bool m_allow_float_window = false; // setted only when wanted to use - not all the time std::optional m_set_window_offset; Emboss::StyleManager m_style_manager; struct FaceName{ wxString wx_name; std::string name_truncated = ""; size_t texture_index = 0; // State for generation of texture // when start generate create share pointers std::shared_ptr> cancel = nullptr; // R/W only on main thread - finalize of job std::shared_ptr is_created = nullptr; }; // Keep sorted list of loadable face names struct Facenames { // flag to keep need of enumeration fonts from OS // false .. wants new enumeration check by Hash // true .. already enumerated(During opened combo box) bool is_init = false; // data of can_load() faces std::vector faces = {}; // Sorter set of Non valid face names in OS std::vector bad = {}; // Configuration of font encoding const wxFontEncoding encoding = wxFontEncoding::wxFONTENCODING_SYSTEM; // Identify if preview texture exists GLuint texture_id = 0; // protection for open too much font files together // Gtk:ERROR:../../../../gtk/gtkiconhelper.c:494:ensure_surface_for_gicon: assertion failed (error == NULL): Failed to load /usr/share/icons/Yaru/48x48/status/image-missing.png: Error opening file /usr/share/icons/Yaru/48x48/status/image-missing.png: Too many open files (g-io-error-quark, 31) // This variable must exist until no CreateFontImageJob is running unsigned int count_opened_font_files = 0; // Configuration for texture height const int count_cached_textures = 32; // index for new generated texture index(must be lower than count_cached_textures) size_t texture_index = 0; // hash created from enumerated font from OS // check when new font was installed size_t hash = 0; } m_face_names; static bool store(const Facenames &facenames); static bool load(Facenames &facenames); // Text to emboss std::string m_text; // actual volume ModelVolume *m_volume; // state of volume when open EmbossGizmo struct EmbossVolume { TriangleMesh tm; TextConfiguration tc; Transform3d tr; std::string name; }; std::optional m_unmodified_volume; // True when m_text contain character unknown by selected font bool m_text_contain_unknown_glyph = false; // cancel for previous update of volume to cancel finalize part std::shared_ptr> m_update_job_cancel; // Rotation gizmo GLGizmoRotate m_rotate_gizmo; // Value is set only when dragging rotation to calculate actual angle std::optional m_rotate_start_angle; // when draging with text object hold screen offset of cursor from object center std::optional m_dragging_mouse_offset; // TODO: it should be accessible by other gizmo too. // May be move to plater? RaycastManager m_raycast_manager; // Only when drag text object it stores world position std::optional m_temp_transformation; // drawing icons GLTexture m_icons_texture; void init_icons(); enum class IconType : unsigned { rename = 0, erase, add, save, undo, italic, unitalic, bold, unbold, system_selector, open_file, // VolumeType icons part, negative, modifier, // automatic calc of icon's count _count }; enum class IconState: unsigned { activable = 0, hovered /*1*/, disabled /*2*/}; void draw_icon(IconType icon, IconState state, ImVec2 size = ImVec2(0,0)); void draw_transparent_icon(); bool draw_clickable(IconType icon, IconState state, IconType hover_icon, IconState hover_state); bool draw_button(IconType icon, bool disable = false); // only temporary solution static const std::string M_ICON_FILENAME; public: /// /// Check if text is last solid part of object /// TODO: move to emboss gui utils /// /// Model volume of Text /// True when object otherwise False static bool is_text_object(const ModelVolume *text); // TODO: move to file utils static std::string get_file_name(const std::string &file_path); }; } // namespace Slic3r::GUI #endif // slic3r_GLGizmoEmboss_hpp_