diff --git a/src/libslic3r/TextConfiguration.hpp b/src/libslic3r/TextConfiguration.hpp
index b333b7cf77..ae8a6c0cb2 100644
--- a/src/libslic3r/TextConfiguration.hpp
+++ b/src/libslic3r/TextConfiguration.hpp
@@ -7,55 +7,87 @@
namespace Slic3r {
-// user defined font property
+///
+/// User modifiable property of text style
+///
struct FontProp
{
// define extra space between letters, negative mean closer letter
- std::optional char_gap;
+ // When not set value is zero and is not stored
+ std::optional char_gap; // [in font point]
+
// define extra space between lines, negative mean closer lines
- std::optional line_gap;
- // Z depth of text [in mm]
- float emboss;
+ // When not set value is zero and is not stored
+ std::optional line_gap; // [in font point]
+
+ // Z depth of text
+ float emboss; // [in mm]
// positive value mean wider character shape
// negative value mean tiner character shape
+ // When not set value is zero and is not stored
std::optional boldness; // [in mm]
// positive value mean italic of character (CW)
// negative value mean CCW skew (unItalic)
- std::optional skew;
+ // When not set value is zero and is not stored
+ std::optional skew; // [ration x:y]
// distance from surface point
// used for move over model surface
- std::optional distance;
+ // When not set value is zero and is not stored
+ std::optional distance; // [in mm]
- // change up vector of font
- std::optional angle;
+ // change up vector direction of font
+ // When not set value is zero and is not stored
+ std::optional angle; // [in radians]
- // TODO: add enum class Align: center/left/right
+ //enum class Align {
+ // left,
+ // right,
+ // center,
+ // top_left,
+ // top_right,
+ // top_center,
+ // bottom_left,
+ // bottom_right,
+ // bottom_center
+ //};
+ //// change pivot of text
+ //// When not set, center is used and is not stored
+ //std::optional align;
//////
// Duplicit data to wxFontDescriptor
// used for store/load .3mf file
//////
- // Height of letter [in mm],
+ // Height of text line (letters)
// duplicit to wxFont::PointSize
- float size_in_mm;
- // Define type of font
+ float size_in_mm; // [in mm]
+
+ // Additional data about font to be able to find substitution,
+ // when same font is not installed
std::optional family;
std::optional face_name;
std::optional style;
std::optional weight;
+ ///
+ /// Only constructor with restricted values
+ ///
+ /// Y size of text [in mm]
+ /// Z size of text [in mm]
FontProp(float line_height = 10.f, float depth = 2.f)
: emboss(depth), size_in_mm(line_height)
{}
bool operator==(const FontProp& other) const {
+ // compare float values
auto is_equal = [](const float &v1, const float &v2) {
return fabs(v1 - v2) < std::numeric_limits::epsilon();
};
+ // compare optional float values
auto is_equal_ = [&is_equal](const std::optional &v1,
const std::optional &v2) {
return (!v1.has_value() && !v2.has_value()) ||
@@ -71,22 +103,31 @@ struct FontProp
}
// undo / redo stack recovery
- template void serialize(Archive &ar)
- {
- ar(char_gap, line_gap, emboss, boldness, skew, size_in_mm, family, face_name, style, weight);
- }
+ //template void serialize(Archive &ar)
+ //{
+ // ar(char_gap, line_gap, emboss, boldness, skew, size_in_mm, family, face_name, style, weight);
+ //}
};
-// represent selected font
-// Name must be human readable is visible in gui
-// (Path + Type) must define how to open font for using on different OS
-// NOTE: OnEdit fix serializations: FontListSerializable, TextConfigurationSerialization
+///
+/// Style of embossed text
+/// (Path + Type) must define how to open font for using on different OS
+/// NOTE: OnEdit fix serializations: FontListSerializable, TextConfigurationSerialization
+///
struct FontItem
{
+ // Human readable name of style it is shown in GUI
std::string name;
+
+ // Define how to open font
+ // Meaning depend on type
std::string path;
+
enum class Type;
+ // Define what is stored in path
Type type;
+
+ // User modification of font style
FontProp prop;
FontItem() : type(Type::undefined){} // set undefined type
@@ -97,17 +138,23 @@ struct FontItem
const std::string &path,
Type type,
const FontProp & prop)
- : name(name), path(path), type(type), prop(prop)
+ : name(name), path(path), type(type), prop(prop) // copy values
{}
// define data stored in path
+ // when wx change way of storing add new descriptor Type
enum class Type {
undefined = 0,
- 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
+ // path is font descriptor generated by wxWidgets
+ wx_win_font_descr, // on Windows
+ wx_lin_font_descr, // on Linux
+ wx_mac_font_descr, // on Max OS
+
+ // TrueTypeFont file loacation on computer
+ // for privacy: only filename is stored into .3mf
+ file_path
};
bool operator==(const FontItem &other) const {
@@ -119,11 +166,11 @@ struct FontItem
;
}
- // undo / redo stack recovery
- template void serialize(Archive &ar)
- {
- ar(name, path, (int) type, prop);
- }
+ //// undo / redo stack recovery
+ //template void serialize(Archive &ar)
+ //{
+ // ar(name, path, (int) type, prop);
+ //}
};
// Font item name inside list is unique
@@ -131,14 +178,17 @@ struct FontItem
// It is stored into AppConfig by FontListSerializable
using FontList = std::vector;
-// define how to create 'Text volume'
-// It is stored into .3mf by TextConfigurationSerialization
-// Also it is stored into undo / redo stack by cereal
+///
+/// Define how to create 'Text volume'
+/// It is stored into .3mf by TextConfigurationSerialization
+/// It is part of ModelVolume optional data
+///
struct TextConfiguration
{
- // define font
+ // Style of embossed text
FontItem font_item;
+ // Embossed text value
std::string text = "None";
TextConfiguration() = default; // optional needs empty constructor
@@ -147,7 +197,7 @@ struct TextConfiguration
{}
// undo / redo stack recovery
- template void serialize(Archive &ar){ ar(text, font_item); }
+ //template void serialize(Archive &ar){ ar(text, font_item); }
};
} // namespace Slic3r
diff --git a/src/slic3r/GUI/Gizmos/GLGizmoEmboss.cpp b/src/slic3r/GUI/Gizmos/GLGizmoEmboss.cpp
index 27f9771796..513f7cfdf3 100644
--- a/src/slic3r/GUI/Gizmos/GLGizmoEmboss.cpp
+++ b/src/slic3r/GUI/Gizmos/GLGizmoEmboss.cpp
@@ -179,19 +179,45 @@ static void draw_place_to_add_text() {
bool GLGizmoEmboss::on_mouse_for_rotation(const wxMouseEvent &mouse_event)
{
+ if (mouse_event.Moving()) return false;
+ if (!m_dragging) return false;
+
+ assert(m_volume != nullptr);
+ assert(m_volume->text_configuration.has_value());
+
+ static std::optional start_angle;
if (mouse_event.Dragging()) {
- if (m_dragging) {
- // temporary rotation
- TransformationType transformation_type(
- TransformationType::Local_Relative_Independent);
- Vec3d rotation(0., 0., m_rotate_gizmo.get_angle());
- m_parent.get_selection().rotate(rotation, transformation_type);
+ auto &angle_opt = m_volume->text_configuration->font_item.prop.angle;
+ if (!start_angle.has_value()) {
+ start_angle = angle_opt.has_value() ? *angle_opt : 0.f;
}
+ // temporary rotation
+ TransformationType transformation_type(
+ TransformationType::Local_Relative_Independent);
+ double angle = m_rotate_gizmo.get_angle();
+ m_parent.get_selection().rotate(Vec3d(0., 0., angle), transformation_type);
+
+ // propagate angle into property
+ angle_opt = static_cast(*start_angle + angle);
+ // move to range <-M_PI, M_PI>
+ if (*angle_opt > M_PI) {
+ *angle_opt -= 2 * M_PI;
+ } else if (*angle_opt < -M_PI) {
+ *angle_opt += 2 * M_PI;
+ }
+ // do not store zero
+ if (std::fabs(*angle_opt) < std::numeric_limits::epsilon())
+ angle_opt.reset();
+
+ // set into activ style
+ if (m_font_manager.is_activ_font()) {
+ m_font_manager.get_font_prop().angle = angle_opt;
+ }
+
} else if (mouse_event.LeftUp()) {
- if (m_dragging) {
- // apply rotation
- m_parent.do_rotate(L("Text-Rotate"));
- }
+ // apply rotation
+ m_parent.do_rotate(L("Text-Rotate"));
+ start_angle.reset();
}
return false;
}
@@ -252,7 +278,7 @@ bool GLGizmoEmboss::on_mouse_for_translate(const wxMouseEvent &mouse_event)
const FontProp& font_prop = m_volume->text_configuration->font_item.prop;
if (font_prop.angle.has_value()) {
- double angle_z = M_PI / 180.0 * (*font_prop.angle);
+ double angle_z = *font_prop.angle;
trmat *= Eigen::AngleAxisd(angle_z, Vec3d::UnitZ());
}
if (font_prop.distance.has_value()) {
@@ -1308,19 +1334,19 @@ void GLGizmoEmboss::draw_advanced()
if (m_imgui->slider_optional_float(_u8L("Italic [Skew ratio]").c_str(), font_prop.skew, -1.f, 1.f, "%.2f", 1.f, false, _L("Italic strength ratio")))
exist_change = true;
- // Property of text configuration
- FontProp &tc_prop = m_volume->text_configuration->font_item.prop;
-
float prev_distance = font_prop.distance.has_value() ?
*font_prop.distance : .0f;
float min_distance = -2 * font_prop.emboss,
max_distance = 2 * font_prop.emboss;
ImGui::SetNextItemWidth(item_width);
if (m_imgui->slider_optional_float(_u8L("Surface distance").c_str(), font_prop.distance,
- min_distance, max_distance, "%.2f mm", 1.f, false, _L("Distance from model surface"))) {
+ min_distance, max_distance, "%.2f mm", 1.f, false, _L("Distance from model surface")) &&
+ m_volume != nullptr && m_volume->text_configuration.has_value()) {
+
+ FontProp& tc_prop = m_volume->text_configuration->font_item.prop;
tc_prop.distance = font_prop.distance;
- float act_distance = font_prop.distance.has_value() ?
- *font_prop.distance : .0f;
+
+ float act_distance = font_prop.distance.has_value() ? *font_prop.distance : .0f;
float diff = act_distance - prev_distance;
Vec3d displacement_rot = Vec3d::UnitZ() * diff;
@@ -1335,23 +1361,35 @@ void GLGizmoEmboss::draw_advanced()
m_parent.do_move(snapshot_name);
}
- float prev_angle = font_prop.angle.has_value() ? *font_prop.angle : .0f;
+ std::optional &angle = font_prop.angle;
+ float prev_angle = angle.has_value() ? *angle : .0f;
+ float angle_deg = prev_angle * 180 / M_PI;
ImGui::SetNextItemWidth(item_width);
- if (m_imgui->slider_optional_float(_u8L("Angle").c_str(), font_prop.angle,
- -180.f, 180.f, u8"%.2f °", 1.f, false, _L("Rotation of text"))) {
- tc_prop.angle = font_prop.angle;
- float act_angle = font_prop.angle.has_value() ? *font_prop.angle : .0f;
- float diff = act_angle-prev_angle;
+ if (m_imgui->slider_float(_u8L("Angle").c_str(), &angle_deg,
+ -180.f, 180.f, u8"%.2f °", 1.f, false, _L("Rotation of text")) ){
+ if (std::fabs(angle_deg) < std::numeric_limits::epsilon()) {
+ angle.reset();
+ } else {
+ // convert to radians
+ angle = angle_deg * M_PI / 180.0;
+ }
+ if (m_volume != nullptr && m_volume->text_configuration.has_value()) {
+ m_volume->text_configuration->font_item.prop.angle = angle;
+ float act_angle = angle.has_value() ? *angle : .0f;
+ float diff = act_angle - prev_angle;
- Selection &selection = m_parent.get_selection();
- selection.start_dragging();
- selection.rotate(Vec3d(0., 0., M_PI / 180.0 * diff), TransformationType::Local);
- selection.stop_dragging();
+ Selection &selection = m_parent.get_selection();
+ selection.start_dragging();
+ selection.rotate(Vec3d(0., 0., diff),
+ TransformationType::Local);
+ selection.stop_dragging();
- std::string snapshot_name; // empty meand no store undo / redo
- // NOTE: it use L instead of _L macro because prefix _ is appended inside function do_move
- //snapshot_name = L("Set surface distance");
- m_parent.do_rotate(snapshot_name);
+ std::string snapshot_name; // empty meand no store undo / redo
+ // NOTE: it use L instead of _L macro because prefix _ is appended
+ // inside function do_move
+ // snapshot_name = L("Set surface distance");
+ m_parent.do_rotate(snapshot_name);
+ }
}
// when more collection add selector