From 706d963f7f1e01d0bd190aa2aeab73d1776600df Mon Sep 17 00:00:00 2001 From: Filip Sykala Date: Tue, 26 Oct 2021 18:56:19 +0200 Subject: [PATCH] Different font type by OS Connect size with wxFont --- src/libslic3r/Emboss.cpp | 3 +- src/libslic3r/Format/3mf.cpp | 132 ++++++++++++----- src/libslic3r/TextConfiguration.hpp | 29 +++- src/slic3r/GUI/Gizmos/GLGizmoEmboss.cpp | 179 +++++++++++++++--------- src/slic3r/GUI/Gizmos/GLGizmoEmboss.hpp | 13 +- 5 files changed, 238 insertions(+), 118 deletions(-) diff --git a/src/libslic3r/Emboss.cpp b/src/libslic3r/Emboss.cpp index 16f3f11d9..4362a26f6 100644 --- a/src/libslic3r/Emboss.cpp +++ b/src/libslic3r/Emboss.cpp @@ -134,7 +134,8 @@ std::optional Private::get_glyph( FontItem Private::create_font_item(std::wstring name, std::wstring path) { return FontItem(boost::nowide::narrow(name.c_str()), - boost::nowide::narrow(path.c_str())); + boost::nowide::narrow(path.c_str()), + FontItem::Type::file_path); } ExPolygons Private::dilate_to_unique_points(ExPolygons &expolygons) diff --git a/src/libslic3r/Format/3mf.cpp b/src/libslic3r/Format/3mf.cpp index a843b3b8c..d74c3c7e9 100644 --- a/src/libslic3r/Format/3mf.cpp +++ b/src/libslic3r/Format/3mf.cpp @@ -148,6 +148,7 @@ static constexpr const char *TEXT_TAG = "emboss"; static constexpr const char *TEXT_DATA_ATTR = "text"; // TextConfiguration::FontItem static constexpr const char *FONT_DESCRIPTOR_ATTR = "font_descriptor"; +static constexpr const char *FONT_DESCRIPTOR_TYPE_ATTR = "font_descriptor_type"; // TextConfiguration::FontProperty static constexpr const char *CHAR_GAP_ATTR = "char_gap"; @@ -1774,6 +1775,37 @@ namespace Slic3r { return true; } + struct TextConfigurationSerialization + { + public: + TextConfigurationSerialization() = delete; + static const std::map to_string; + static const std::map to_type; + + static FontItem::Type get_type(const std::string &type_string) { + auto it = to_type.find(type_string); + return (it != to_type.end()) ? it->second : FontItem::Type::undefined; + } + + static void to_xml(std::stringstream &stream, const TextConfiguration &tc); + static std::optional read(const char **attributes, unsigned int num_attributes); + + /// + /// Create map with swaped key-value + /// IMPROVE: Move to map utils + /// + /// Input map + /// Map with swapped key-value + template + static std::map create_oposit_map( + const std::map &map) + { + std::map result; + for (const auto &it : map) result[it.second] = it.first; + return result; + } + }; + bool _3MF_Importer::_handle_start_text_configuration(const char **attributes, unsigned int num_attributes) { IdToMetadataMap::iterator object = m_objects_metadata.find(m_curr_config.object_id); @@ -1786,22 +1818,8 @@ namespace Slic3r { return false; } ObjectMetadata::VolumeMetadata& volume = object->second.volumes.back(); - - std::string text = get_attribute_value_string(attributes, num_attributes, TEXT_DATA_ATTR); - std::string font_name = ""; - std::string font_descriptor = get_attribute_value_string(attributes, num_attributes, FONT_DESCRIPTOR_ATTR); - FontItem::Type font_type = FontItem::Type::loaded_from_3mf; // default font type - FontItem fi(font_name, font_descriptor, font_type); - - FontProp fp; - fp.char_gap = get_attribute_value_int(attributes, num_attributes, CHAR_GAP_ATTR); - fp.line_gap = get_attribute_value_int(attributes, num_attributes, LINE_GAP_ATTR); - fp.flatness = get_attribute_value_float(attributes, num_attributes, FLATNESS_ATTR); - fp.size_in_mm = get_attribute_value_float(attributes, num_attributes, LINE_HEIGHT_ATTR); - fp.emboss = get_attribute_value_float(attributes, num_attributes, DEPTH_ATTR); - - volume.text_configuration = TextConfiguration(fi, fp, text); - return true; + volume.text_configuration = TextConfigurationSerialization::read(attributes, num_attributes); + return volume.text_configuration.has_value(); } bool _3MF_Importer::_handle_end_text_configuration() { @@ -2233,6 +2251,7 @@ namespace Slic3r { bool _add_print_config_file_to_archive(mz_zip_archive& archive, const DynamicPrintConfig &config); bool _add_model_config_file_to_archive(mz_zip_archive& archive, const Model& model, const IdToObjectDataMap &objects_data); bool _add_custom_gcode_per_print_z_file_to_archive(mz_zip_archive& archive, Model& model, const DynamicPrintConfig* config); + void _add_text_configuration(std::stringstream& stream, const TextConfiguration& cfg); }; bool _3MF_Exporter::save_model_to_file(const std::string& filename, Model& model, const DynamicPrintConfig* config, bool fullpath_sources, const ThumbnailData* thumbnail_data, bool zip64) @@ -3090,24 +3109,8 @@ namespace Slic3r { } // stores volume's text data - if (volume->text_configuration.has_value()) { - - const TextConfiguration& tc = *volume->text_configuration; - stream << " <" << TEXT_TAG << " "; - - stream << TEXT_DATA_ATTR << "=\"" << xml_escape(tc.text) << "\" "; - // font item - const auto &fi = tc.font_item; - stream << FONT_DESCRIPTOR_ATTR << "=\"" << fi.path << "\" "; - // font property - const auto &fp = tc.font_prop; - stream << CHAR_GAP_ATTR << "=\"" << fp.char_gap << "\" "; - stream << LINE_GAP_ATTR << "=\"" << fp.line_gap << "\" "; - stream << FLATNESS_ATTR << "=\"" << fp.flatness << "\" "; - stream << LINE_HEIGHT_ATTR << "=\"" << fp.size_in_mm << "\" "; - stream << DEPTH_ATTR << "=\"" << fp.emboss << "\" "; - stream << "/>\n"; // end TEXT_TAG - } + if (volume->text_configuration.has_value()) + _add_text_configuration(stream, *volume->text_configuration); // stores mesh's statistics const RepairedMeshErrors& stats = volume->mesh().stats().repaired_errors; @@ -3188,6 +3191,12 @@ bool _3MF_Exporter::_add_custom_gcode_per_print_z_file_to_archive( mz_zip_archiv return true; } +void _3MF_Exporter::_add_text_configuration(std::stringstream & stream, + const TextConfiguration &tc) +{ + TextConfigurationSerialization::to_xml(stream, tc); +} + // Perform conversions based on the config values available. //FIXME provide a version of PrusaSlicer that stored the project file (3MF). static void handle_legacy_project_loaded(unsigned int version_project_file, DynamicPrintConfig& config) @@ -3230,4 +3239,59 @@ bool store_3mf(const char* path, Model* model, const DynamicPrintConfig* config, return res; } + +/// +/// TextConfiguration serialization +/// +const std::map TextConfigurationSerialization::to_string = { + {FontItem::Type::file_path, "file_name"}, + {FontItem::Type::wx_win_font_descr, "wxFontDescriptor_Windows"}, + {FontItem::Type::wx_lin_font_descr, "wxFontDescriptor_Linux"}, + {FontItem::Type::wx_mac_font_descr, "wxFontDescriptor_MacOsX"} +}; + +const std::map TextConfigurationSerialization::to_type = +TextConfigurationSerialization::create_oposit_map(TextConfigurationSerialization::to_string); + +void TextConfigurationSerialization::to_xml(std::stringstream &stream, const TextConfiguration &tc) +{ + stream << " <" << TEXT_TAG << " "; + + stream << TEXT_DATA_ATTR << "=\"" << xml_escape(tc.text) << "\" "; + // font item + const FontItem &fi = tc.font_item; + stream << FONT_DESCRIPTOR_ATTR << "=\"" << fi.path << "\" "; + stream << FONT_DESCRIPTOR_TYPE_ATTR << "=\"" << TextConfigurationSerialization::to_string.at(fi.type) << "\" "; + + // font property + const FontProp &fp = tc.font_prop; + stream << CHAR_GAP_ATTR << "=\"" << fp.char_gap << "\" "; + stream << LINE_GAP_ATTR << "=\"" << fp.line_gap << "\" "; + stream << FLATNESS_ATTR << "=\"" << fp.flatness << "\" "; + stream << LINE_HEIGHT_ATTR << "=\"" << fp.size_in_mm << "\" "; + stream << DEPTH_ATTR << "=\"" << fp.emboss << "\" "; + + stream << "/>\n"; // end TEXT_TAG +} + +std::optional TextConfigurationSerialization::read(const char **attributes, unsigned int num_attributes) +{ + std::string text = get_attribute_value_string(attributes, num_attributes, TEXT_DATA_ATTR); + std::string font_name = ""; + std::string font_descriptor = get_attribute_value_string(attributes, num_attributes, FONT_DESCRIPTOR_ATTR); + std::string type_str = get_attribute_value_string(attributes, num_attributes, FONT_DESCRIPTOR_TYPE_ATTR); + FontItem::Type type = TextConfigurationSerialization::get_type(type_str); + FontItem fi(font_name, font_descriptor, type); + + FontProp fp; + fp.char_gap = get_attribute_value_int(attributes, num_attributes, CHAR_GAP_ATTR); + fp.line_gap = get_attribute_value_int(attributes, num_attributes, LINE_GAP_ATTR); + fp.flatness = get_attribute_value_float(attributes, num_attributes, FLATNESS_ATTR); + fp.size_in_mm = get_attribute_value_float(attributes, num_attributes, LINE_HEIGHT_ATTR); + fp.emboss = get_attribute_value_float(attributes, num_attributes, DEPTH_ATTR); + + return TextConfiguration(fi, fp, text); +} + + } // namespace Slic3r diff --git a/src/libslic3r/TextConfiguration.hpp b/src/libslic3r/TextConfiguration.hpp index 259b4ac97..f4535ca98 100644 --- a/src/libslic3r/TextConfiguration.hpp +++ b/src/libslic3r/TextConfiguration.hpp @@ -3,8 +3,18 @@ #include #include +#include namespace Slic3r { + +// additional information stored/load to/from .3mf file +// to be platform independent +struct Font3mfDesc +{ + std::string family; + + Font3mfDesc() = default; +}; // represent selected font // Name must be human readable is visible in gui @@ -16,17 +26,21 @@ struct FontItem enum class Type; Type type; - FontItem() : type(Type::undefined) {} - FontItem(const std::string &name, const std::string &path, Type type = Type::file_path) + std::optional font3mf; // description from 3mf + + FontItem() : type(Type::undefined){} // set undefined type + FontItem(const std::string &name, const std::string &path, Type type) : name(name), path(path), type(type) {} - // way of load font described in path string + // define data stored in path enum class Type { undefined = 0, - file_path, // path is file loacation on computer - no move between computers - wx_font_descr, // path is font descriptor generated by wxWidgets - limits for os/language move - loaded_from_3mf + file_path, // TrueTypeFont file loacation on computer - for privacy: path is NOT stored into 3mf + // wx font descriptors are platform dependent + wx_win_font_descr, // path is font descriptor generated by wxWidgets on windows + wx_lin_font_descr, // path is font descriptor generated by wxWidgets on windows + wx_mac_font_descr // path is font descriptor generated by wxWidgets on windows }; }; using FontList = std::vector; @@ -65,7 +79,8 @@ struct TextConfiguration const std::string &text) : font_item(font_item), font_prop(font_prop), text(text) {} -}; +}; + } // namespace Slic3r #endif // slic3r_TextConfiguration_hpp_ diff --git a/src/slic3r/GUI/Gizmos/GLGizmoEmboss.cpp b/src/slic3r/GUI/Gizmos/GLGizmoEmboss.cpp index 2935a0ad6..950087d4d 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoEmboss.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoEmboss.cpp @@ -25,27 +25,17 @@ #include -#ifdef __APPLE__ +#ifdef _WIN32 +// no specific include +#elif defined(__APPLE__) #include #include #include -#define USE_FONT_DIALOG -#endif // apple - -#ifdef __linux__ -//#ifdef __WXGTK__ -#define FontConfigExist -#endif - -#ifdef FontConfigExist +#else // #ifdef __linux__ +// Font Config must exist #include #include -#define USE_FONT_DIALOG -#endif // FontConfigExist - -#ifdef _WIN32 -#define USE_FONT_DIALOG -#endif // _WIN32 +#endif // uncomment for easier debug // #define ALLOW_DEBUG_MODE @@ -61,6 +51,7 @@ public: // Must be in gui because of wxWidget static std::optional load_font(FontItem &fi); + static FontItem::Type get_actual_type(); static FontItem get_font_item(const wxFont &font); // load font used by Operating system as default GUI @@ -459,6 +450,13 @@ void GLGizmoEmboss::draw_window() } #endif // ALLOW_DEBUG_MODE + std::string descriptor = m_font_list[m_font_selected].path; + wxFont wx_font = WxFontUtils::load_wxFont(descriptor); + + ImGui::Text(("actual descriptor is " + descriptor).c_str()); + //wx_font. + + if (!m_font.has_value()) { ImGui::Text(_u8L("Warning: No font is selected. Select correct one.").c_str()); } @@ -587,6 +585,13 @@ void GLGizmoEmboss::draw_text_input() void GLGizmoEmboss::draw_advanced() { if (ImGui::InputFloat(_u8L("Size[in mm]").c_str(), &m_font_prop.size_in_mm)) { if (m_font_prop.size_in_mm < 0.1) m_font_prop.size_in_mm = 10; + // store font size into path + FontItem& fi = m_font_list[m_font_selected]; + if (fi.type == WxFontUtils::get_actual_type()) { + wxFont font = WxFontUtils::load_wxFont(fi.path); + font.SetPointSize(m_font_prop.size_in_mm); + fi.path = WxFontUtils::store_wxFont(font); + } load_imgui_font(); process(); } @@ -782,7 +787,7 @@ bool GLGizmoEmboss::choose_font_by_wxdialog() data.RestrictSelection(wxFONTRESTRICT_SCALABLE); // set previous selected font FontItem &selected_font_item = m_font_list[m_font_selected]; - if (selected_font_item.type == FontItem::Type::wx_font_descr) { + if (selected_font_item.type == WxFontUtils::get_actual_type()) { wxFont selected_font = WxFontUtils::load_wxFont(selected_font_item.path); data.SetInitialFont(selected_font); } @@ -836,7 +841,7 @@ bool GLGizmoEmboss::choose_true_type_file() for (auto &input_file : input_files) { std::string path = std::string(input_file.c_str()); std::string name = get_file_name(path); - m_font_list.emplace_back(name, path); + m_font_list.emplace_back(name, path, FontItem::Type::file_path); // set first valid added font as active if (!font_loaded) { @@ -881,14 +886,6 @@ bool GLGizmoEmboss::choose_svg_file() return add_volume(name, its); } -std::string GLGizmoEmboss::get_file_name(const std::string &file_path) { - size_t pos_last_delimiter = file_path.find_last_of('\\'); - size_t pos_point = file_path.find_last_of('.'); - size_t offset = pos_last_delimiter + 1; - size_t count = pos_point - pos_last_delimiter - 1; - return file_path.substr(offset, count); -} - TextConfiguration GLGizmoEmboss::create_configuration() { return TextConfiguration(m_font_list[m_font_selected], m_font_prop, m_text); } @@ -971,33 +968,6 @@ void GLGizmoEmboss::notify_cant_load_font(const FontItem &font_item) { notification_manager->push_notification(type, level, text); } -std::string GLGizmoEmboss::imgui_trunc(const std::string &text, float width) -{ - static const char *tail = " .."; - float tail_width = ImGui::CalcTextSize(tail).x; - float text_width = ImGui::CalcTextSize(text.c_str()).x; - if (text_width < width) return text; - float letter_width = ImGui::CalcTextSize("n").x; - float allowed_width = width-tail_width; - unsigned count_letter = static_cast(allowed_width / letter_width); - text_width = ImGui::CalcTextSize(text.substr(0, count_letter).c_str()).x; - if (text_width < allowed_width) { - // increase letter count - do { - ++count_letter; - text_width = ImGui::CalcTextSize(text.substr(0, count_letter).c_str()).x; - } while (text_width < allowed_width); - --count_letter; - } else { - // decrease letter count - do { - --count_letter; - text_width = ImGui::CalcTextSize(text.substr(0, count_letter).c_str()).x; - } while (text_width > allowed_width); - } - return text.substr(0, count_letter) + tail; -} - std::string GLGizmoEmboss::create_volume_name() { const size_t &max_len = m_gui_cfg->max_count_char_in_volume_name; @@ -1113,8 +1083,11 @@ void GLGizmoEmboss::store_font_list() { AppConfig *cfg = wxGetApp().app_config; unsigned index = 1; - for (const FontItem &fi : m_font_list) + for (const FontItem &fi : m_font_list) { + // skip file paths + fonts from other OS + if (fi.type != WxFontUtils::get_actual_type()) continue; set_font_item(*cfg, fi, index++); + } // remove rest of font sections std::string section_name = get_app_config_font_section(index); @@ -1143,7 +1116,7 @@ std::optional GLGizmoEmboss::get_font_item( static const std::string default_name = "font_name"; const std::string& name = (name_it == app_cfg_section.end()) ? default_name : name_it->second; - return FontItem(name, path, FontItem::Type::wx_font_descr); + return FontItem(name, path, WxFontUtils::get_actual_type()); } void GLGizmoEmboss::set_font_item(AppConfig &cfg, const FontItem &fi, unsigned index) { @@ -1153,20 +1126,73 @@ void GLGizmoEmboss::set_font_item(AppConfig &cfg, const FontItem &fi, unsigned i cfg.set(section_name, APP_CONFIG_FONT_DESCRIPTOR, fi.path); } +std::string GLGizmoEmboss::get_file_name(const std::string &file_path) +{ + size_t pos_last_delimiter = file_path.find_last_of('\\'); + size_t pos_point = file_path.find_last_of('.'); + size_t offset = pos_last_delimiter + 1; + size_t count = pos_point - pos_last_delimiter - 1; + return file_path.substr(offset, count); +} + +std::string GLGizmoEmboss::imgui_trunc(const std::string &text, float width) +{ + static const char *tail = " .."; + float tail_width = ImGui::CalcTextSize(tail).x; + float text_width = ImGui::CalcTextSize(text.c_str()).x; + if (text_width < width) return text; + float letter_width = ImGui::CalcTextSize("n").x; + float allowed_width = width - tail_width; + unsigned count_letter = static_cast(allowed_width / + letter_width); + text_width = ImGui::CalcTextSize(text.substr(0, count_letter).c_str()).x; + if (text_width < allowed_width) { + // increase letter count + do { + ++count_letter; + text_width = + ImGui::CalcTextSize(text.substr(0, count_letter).c_str()).x; + } while (text_width < allowed_width); + --count_letter; + } else { + // decrease letter count + do { + --count_letter; + text_width = + ImGui::CalcTextSize(text.substr(0, count_letter).c_str()).x; + } while (text_width > allowed_width); + } + return text.substr(0, count_letter) + tail; +} + +/// +/// WxFontUtils - Start definition +/// + std::optional WxFontUtils::load_font(FontItem &fi) { - switch (fi.type) { - case FontItem::Type::file_path: - return Emboss::load_font(fi.path.c_str()); - case FontItem::Type::wx_font_descr: - return WxFontUtils::load_font(WxFontUtils::load_wxFont(fi.path)); - case FontItem::Type::loaded_from_3mf: { - wxFont font = WxFontUtils::load_wxFont(fi.path); - // fix name - fi.name = get_human_readable_name(font); - fi.type = FontItem::Type::wx_font_descr; - return WxFontUtils::load_font(font); + if (fi.type == get_actual_type()) { + wxFont font = load_wxFont(fi.path); + // fill font name after load from .3mf + if (fi.name.empty()) fi.name = get_human_readable_name(font); + return load_font(load_wxFont(fi.path)); } + + if (fi.type == FontItem::Type::file_path) { + // fill font name after load from .3mf + if (fi.name.empty()) + fi.name = Slic3r::GUI::GLGizmoEmboss::get_file_name(fi.path); + return Emboss::load_font(fi.path.c_str()); + } + + // TODO: How to get more info from source 3mf file? + + + switch (fi.type) { + case FontItem::Type::wx_lin_font_descr: + case FontItem::Type::wx_win_font_descr: + + case FontItem::Type::file_path: case FontItem::Type::undefined: default: return {}; @@ -1201,16 +1227,29 @@ std::optional WxFontUtils::load_font(const wxFont &font) #else // HERE is place to add implementation for another platform // to convert wxFont to font data as windows or font file path as linux - // Do not forget to allow macro USE_FONT_DIALOG return {}; #endif } +FontItem::Type WxFontUtils::get_actual_type() { +#ifdef _WIN32 + return FontItem::Type::wx_win_font_descr; +#elif __APPLE__ + return FontItem::Type::wx_mac_font_descr; +#elif defined(FontConfigExist) + return FontItem::Type::wx_mac_font_descr; +#else + return FontItem::Type::undefined; +#endif +} + FontItem WxFontUtils::get_font_item(const wxFont &font) { - std::string name = get_human_readable_name(font); - std::string fontDesc = store_wxFont(font); - return FontItem(name, fontDesc, FontItem::Type::wx_font_descr); + std::string name = get_human_readable_name(font); + std::string fontDesc = store_wxFont(font); + FontItem::Type type = get_actual_type(); + //wxFont f = font; // copy + return FontItem(name, fontDesc, type); } FontItem WxFontUtils::get_os_font() diff --git a/src/slic3r/GUI/Gizmos/GLGizmoEmboss.hpp b/src/slic3r/GUI/Gizmos/GLGizmoEmboss.hpp index ff3d91173..9f0cf637e 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoEmboss.hpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoEmboss.hpp @@ -66,9 +66,6 @@ private: bool choose_true_type_file(); bool choose_svg_file(); - // TODO: move to file utils - static std::string get_file_name(const std::string &file_path); - // Create object described how to make a Volume TextConfiguration create_configuration(); bool load_configuration(ModelVolume *volume); @@ -77,9 +74,6 @@ private: bool notify_unknown_font_type(ModelVolume *volume); void notify_cant_load_font(const FontItem &font_item); - // TODO: Move to imgui utils - std::string imgui_trunc(const std::string &text, float width); - std::string create_volume_name(); // This configs holds GUI layout size given by translated texts. @@ -151,6 +145,13 @@ private: // only temporary solution static const std::string M_ICON_FILENAME; + +public: + // TODO: move to file utils + static std::string get_file_name(const std::string &file_path); + + // TODO: Move to imgui utils + std::string imgui_trunc(const std::string &text, float width); }; } // namespace Slic3r::GUI