diff --git a/src/libslic3r/Emboss.cpp b/src/libslic3r/Emboss.cpp
index bfd377fa02..7352516633 100644
--- a/src/libslic3r/Emboss.cpp
+++ b/src/libslic3r/Emboss.cpp
@@ -1287,12 +1287,14 @@ ExPolygons Emboss::text2shapes(FontFileWithCache &font_with_cache, const char *t
namespace {
///
-/// Align expolygons by type
+/// Align shape against pivot
///
-/// Type of alignment
-/// shapes to align
-/// Same size as shape for align per line(detect of end line - '\n')
-void align_shape(FontProp::Align type, std::vector &shape, const std::wstring &text);
+/// Horizontal and vertical alignment
+/// Shapes to align
+/// Prerequisities: shapes are aligned left top
+/// To detect end of lines
+/// Height of line for align[in font points]
+void align_shape(FontProp::Align type, std::vector &shape, const std::wstring &text, int line_height);
}
std::vector Emboss::text2vshapes(FontFileWithCache &font_with_cache, const std::wstring& text, const FontProp &font_prop, const std::function& was_canceled){
@@ -1317,7 +1319,7 @@ std::vector Emboss::text2vshapes(FontFileWithCache &font_with_cache,
result.emplace_back(letter2shapes(letter, cursor, font_with_cache, font_prop, font_info_cache));
}
- align_shape(font_prop.align, result, text);
+ align_shape(font_prop.align, result, text, get_line_height(font, font_prop));
return result;
}
@@ -1927,47 +1929,37 @@ PolygonPoints Emboss::sample_slice(const TextLine &slice, const BoundingBoxes &b
}
namespace {
-int32_t get_align_y_offset(FontProp::Align type, const BoundingBox &bb){
- switch (type) {
- case Slic3r::FontProp::Align::first_line_left:
- case Slic3r::FontProp::Align::first_line_right:
- case Slic3r::FontProp::Align::first_line_center: break; // No change
- case Slic3r::FontProp::Align::center_left:
- case Slic3r::FontProp::Align::center_right:
- case Slic3r::FontProp::Align::center_center: return -bb.center().y();
- case Slic3r::FontProp::Align::top_left:
- case Slic3r::FontProp::Align::top_right:
- case Slic3r::FontProp::Align::top_center: return -bb.max.y(); break; // direction of Y in 2d is from top to bottom
- case Slic3r::FontProp::Align::bottom_left:
- case Slic3r::FontProp::Align::bottom_right:
- case Slic3r::FontProp::Align::bottom_center: return -bb.min.y(); // direction of Y in 2d is from top to bottom
- default: break;
+int32_t get_align_y_offset(FontProp::VerticalAlign align, int count_lines, int line_height)
+{
+ // direction of Y in 2d is from top to bottom
+ // zero is on base line of first line
+ switch (align) {
+ case FontProp::VerticalAlign::center:
+ return ((count_lines-1) / 2) * line_height
+ + ((count_lines % 2 == 0) ? (line_height / 2) : 0);
+ case FontProp::VerticalAlign::bottom:
+ return (count_lines-1) * line_height;
+ case FontProp::VerticalAlign::top: // no change
+ default:
+ break;
}
return 0;
}
-int32_t get_align_x_offset(FontProp::Align type, const BoundingBox &shape_bb, const BoundingBox &line_bb)
+int32_t get_align_x_offset(FontProp::HorizontalAlign align, const BoundingBox &shape_bb, const BoundingBox &line_bb)
{
- switch (type) {
- case Slic3r::FontProp::Align::first_line_center:
- case Slic3r::FontProp::Align::center_center:
- case Slic3r::FontProp::Align::top_center:
- case Slic3r::FontProp::Align::bottom_center: return -shape_bb.center().x() + (shape_bb.size().x() - line_bb.size().x())/2;
- case Slic3r::FontProp::Align::first_line_left: break; // special case do not use offset
- case Slic3r::FontProp::Align::center_left:
- case Slic3r::FontProp::Align::top_left:
- case Slic3r::FontProp::Align::bottom_left: return -shape_bb.min.x();
- case Slic3r::FontProp::Align::first_line_right:
- case Slic3r::FontProp::Align::center_right:
- case Slic3r::FontProp::Align::top_right:
- case Slic3r::FontProp::Align::bottom_right: return -shape_bb.max.x() + (shape_bb.size().x() - line_bb.size().x());
+ switch (align) {
+ case FontProp::HorizontalAlign::right: return -shape_bb.max.x() + (shape_bb.size().x() - line_bb.size().x());
+ case FontProp::HorizontalAlign::center: return -shape_bb.center().x() + (shape_bb.size().x() - line_bb.size().x()) / 2;
+ case FontProp::HorizontalAlign::left: // no change
default: break;
}
return 0;
}
-void align_shape(FontProp::Align type, std::vector &shapes, const std::wstring &text)
+void align_shape(FontProp::Align type, std::vector &shapes, const std::wstring &text, int line_height)
{
- if (type == FontProp::Align::first_line_left)
+ constexpr FontProp::Align no_change(FontProp::HorizontalAlign::left, FontProp::VerticalAlign::top);
+ if (type == no_change)
return; // no alignment
BoundingBox shape_bb;
@@ -1982,13 +1974,13 @@ void align_shape(FontProp::Align type, std::vector &shapes, const st
};
Point offset(
- get_align_x_offset(type, shape_bb, get_line_bb(0)),
- get_align_y_offset(type, shape_bb));
+ get_align_x_offset(type.first, shape_bb, get_line_bb(0)),
+ get_align_y_offset(type.second, get_count_lines(text), line_height));
assert(shapes.size() == text.length());
for (size_t i = 0; i < shapes.size(); ++i) {
- wchar_t letter = text[i];
+ wchar_t letter = text[i];
if (letter == '\n'){
- offset.x() = get_align_x_offset(type, shape_bb, get_line_bb(i+1));
+ offset.x() = get_align_x_offset(type.first, shape_bb, get_line_bb(i+1));
continue;
}
ExPolygons &shape = shapes[i];
diff --git a/src/libslic3r/Format/3mf.cpp b/src/libslic3r/Format/3mf.cpp
index dfe2a90a4c..f3ad9535d4 100644
--- a/src/libslic3r/Format/3mf.cpp
+++ b/src/libslic3r/Format/3mf.cpp
@@ -164,7 +164,8 @@ static constexpr const char *SKEW_ATTR = "skew";
static constexpr const char *DISTANCE_ATTR = "distance";
static constexpr const char *ANGLE_ATTR = "angle";
static constexpr const char *PER_GLYPH_ATTR = "per_glyph";
-static constexpr const char *ALIGN_ATTR = "align";
+static constexpr const char *HORIZONTAL_ALIGN_ATTR = "horizontal";
+static constexpr const char *VERTICAL_ALIGN_ATTR = "vertical";
static constexpr const char *COLLECTION_NUMBER_ATTR = "collection";
static constexpr const char *FONT_FAMILY_ATTR = "family";
@@ -3534,8 +3535,8 @@ void TextConfigurationSerialization::to_xml(std::stringstream &stream, const Tex
stream << ANGLE_ATTR << "=\"" << *fp.angle << "\" ";
if (fp.per_glyph)
stream << PER_GLYPH_ATTR << "=\"" << 1 << "\" ";
- if (fp.align != FontProp().align) // differ to default value? back compatibility
- stream << ALIGN_ATTR << "=\"" << static_cast(fp.align) << "\" ";
+ stream << HORIZONTAL_ALIGN_ATTR << "=\"" << static_cast(fp.align.first) << "\" ";
+ stream << VERTICAL_ALIGN_ATTR << "=\"" << static_cast(fp.align.second) << "\" ";
if (fp.collection_number.has_value())
stream << COLLECTION_NUMBER_ATTR << "=\"" << *fp.collection_number << "\" ";
// font descriptor
@@ -3617,8 +3618,12 @@ std::optional TextConfigurationSerialization::read(const char
fp.angle = angle;
int per_glyph = get_attribute_value_int(attributes, num_attributes, PER_GLYPH_ATTR);
if (per_glyph == 1) fp.per_glyph = true;
- int align = get_attribute_value_int(attributes, num_attributes, ALIGN_ATTR);
- fp.align = static_cast(align);
+
+ int horizontal = get_attribute_value_int(attributes, num_attributes, HORIZONTAL_ALIGN_ATTR);
+ int vertical = get_attribute_value_int(attributes, num_attributes, VERTICAL_ALIGN_ATTR);
+ fp.align = FontProp::Align(
+ static_cast(horizontal),
+ static_cast(vertical));
int collection_number = get_attribute_value_int(attributes, num_attributes, COLLECTION_NUMBER_ATTR);
if (collection_number > 0) fp.collection_number = static_cast(collection_number);
diff --git a/src/libslic3r/TextConfiguration.hpp b/src/libslic3r/TextConfiguration.hpp
index 79712b8795..f60096edad 100644
--- a/src/libslic3r/TextConfiguration.hpp
+++ b/src/libslic3r/TextConfiguration.hpp
@@ -63,27 +63,14 @@ struct FontProp
// Distiguish projection per glyph
bool per_glyph;
- // Enumerate type of allowed text align
- enum class Align {
- // NOTE: default value must be zero - 3mf store
- first_line_center = 0, // use Y zero same as first letter
- first_line_left, // it depends on position of zero for first letter (no shape move)
- first_line_right, // use Y zero same as first letter
- center_center,
- center_left,
- center_right,
- top_center,
- top_left,
- top_right,
- bottom_center,
- bottom_left,
- bottom_right
- };
-
+ // NOTE: way of serialize to 3mf force that zero must be default value
+ enum class HorizontalAlign { left = 0, center, right };
+ enum class VerticalAlign { top = 0, center, bottom };
+ using Align = std::pair;
// change pivot of text
// When not set, center is used and is not stored
- Align align = Align::first_line_center;
-
+ Align align = Align(HorizontalAlign::left, VerticalAlign::top);
+
//////
// Duplicit data to wxFontDescriptor
// used for store/load .3mf file
@@ -126,7 +113,7 @@ struct FontProp
// undo / redo stack recovery
template void save(Archive &ar) const
{
- ar(emboss, use_surface, size_in_mm, per_glyph, align);
+ ar(emboss, use_surface, size_in_mm, per_glyph, align.first, align.second);
cereal::save(ar, char_gap);
cereal::save(ar, line_gap);
cereal::save(ar, boldness);
@@ -141,7 +128,7 @@ struct FontProp
}
template void load(Archive &ar)
{
- ar(emboss, use_surface, size_in_mm, per_glyph, align);
+ ar(emboss, use_surface, size_in_mm, per_glyph, align.first, align.second);
cereal::load(ar, char_gap);
cereal::load(ar, line_gap);
cereal::load(ar, boldness);
diff --git a/src/slic3r/GUI/Gizmos/GLGizmoEmboss.cpp b/src/slic3r/GUI/Gizmos/GLGizmoEmboss.cpp
index ffbb3c1e98..bd78b66193 100644
--- a/src/slic3r/GUI/Gizmos/GLGizmoEmboss.cpp
+++ b/src/slic3r/GUI/Gizmos/GLGizmoEmboss.cpp
@@ -3063,39 +3063,6 @@ void GLGizmoEmboss::do_rotate(float relative_z_angle)
m_parent.do_rotate(snapshot_name);
}
-namespace{
-bool is_left( FontProp::Align align){ return align == FontProp::Align::bottom_left || align == FontProp::Align::center_left || align == FontProp::Align::top_left; }
-bool is_center_h(FontProp::Align align){ return align == FontProp::Align::bottom_center || align == FontProp::Align::center_center || align == FontProp::Align::top_center; }
-bool is_right( FontProp::Align align){ return align == FontProp::Align::bottom_right || align == FontProp::Align::center_right || align == FontProp::Align::top_right; }
-bool is_top( FontProp::Align align){ return align == FontProp::Align::top_left || align == FontProp::Align::top_center || align == FontProp::Align::top_right; }
-bool is_center_v(FontProp::Align align){ return align == FontProp::Align::center_left || align == FontProp::Align::center_center || align == FontProp::Align::center_right; }
-bool is_bottom( FontProp::Align align){ return align == FontProp::Align::bottom_left || align == FontProp::Align::bottom_center || align == FontProp::Align::bottom_right; }
-void to_left(FontProp::Align &align){
- align = (align == FontProp::Align::bottom_right || align == FontProp::Align::bottom_center) ? FontProp::Align::bottom_left :
- (align == FontProp::Align::center_right || align == FontProp::Align::center_center) ? FontProp::Align::center_left :
- FontProp::Align::top_left;}
-void to_center_h(FontProp::Align &align){
- align = (align == FontProp::Align::bottom_right || align == FontProp::Align::bottom_left) ? FontProp::Align::bottom_center :
- (align == FontProp::Align::center_right || align == FontProp::Align::center_left) ? FontProp::Align::center_center :
- FontProp::Align::top_center;}
-void to_right(FontProp::Align &align){
- align = (align == FontProp::Align::bottom_left || align == FontProp::Align::bottom_center) ? FontProp::Align::bottom_right :
- (align == FontProp::Align::center_left || align == FontProp::Align::center_center) ? FontProp::Align::center_right :
- FontProp::Align::top_right;}
-void to_top(FontProp::Align &align){
- align = (align == FontProp::Align::bottom_left || align == FontProp::Align::center_left) ? FontProp::Align::top_left :
- (align == FontProp::Align::bottom_right || align == FontProp::Align::center_right) ? FontProp::Align::top_right :
- FontProp::Align::top_center;}
-void to_center_v(FontProp::Align &align){
- align = (align == FontProp::Align::bottom_left || align == FontProp::Align::top_left) ? FontProp::Align::center_left :
- (align == FontProp::Align::bottom_right || align == FontProp::Align::top_right) ? FontProp::Align::center_right :
- FontProp::Align::center_center;}
-void to_bottom(FontProp::Align &align){
- align = (align == FontProp::Align::top_left || align == FontProp::Align::center_left) ? FontProp::Align::bottom_left :
- (align == FontProp::Align::top_right || align == FontProp::Align::center_right) ? FontProp::Align::bottom_right :
- FontProp::Align::bottom_center;}
-}
-
void GLGizmoEmboss::draw_advanced()
{
const auto &ff = m_style_manager.get_font_file_with_cache();
@@ -3186,51 +3153,37 @@ void GLGizmoEmboss::draw_advanced()
ImGui::SetTooltip("TEST PURPOSE ONLY\nMove base line (up/down) for allign letters");
m_imgui->disabled_end(); // !per_glyph
- const FontProp::Align * def_align = stored_style ? &stored_style->prop.align : nullptr;
- float undo_offset = ImGui::GetStyle().FramePadding.x;
- //auto draw = [&selected_align, gui_cfg = m_gui_cfg]() {
- // // order must match align enum
- // const char* align_names[] = { "first_line_center",
- // "first_line_left",
- // "first_line_right",
- // "center_center",
- // "center_left",
- // "center_right",
- // "top_center",
- // "top_left",
- // "top_right",
- // "bottom_center",
- // "bottom_left",
- // "bottom_right"};
- // ImGui::SameLine(gui_cfg->advanced_input_offset);
- // ImGui::SetNextItemWidth(gui_cfg->input_width);
- // return ImGui::Combo("##text_alignment", &selected_align, align_names, IM_ARRAYSIZE(align_names));
- //};
-
auto draw_align = [&align = font_prop.align, gui_cfg = m_gui_cfg, &icons = m_icons]() {
bool is_change = false;
ImGui::SameLine(gui_cfg->advanced_input_offset);
- if (is_left(align)) Slic3r::GUI::draw(get_icon(icons, IconType::align_horizontal_left, IconState::hovered));
- else if (draw_button(icons, IconType::align_horizontal_left)) { to_left(align); is_change = true; }
+ if (align.first==FontProp::HorizontalAlign::left) draw(get_icon(icons, IconType::align_horizontal_left, IconState::hovered));
+ else if (draw_button(icons, IconType::align_horizontal_left)) { align.first=FontProp::HorizontalAlign::left; is_change = true; }
+ else if (ImGui::IsItemHovered()) ImGui::SetTooltip("%s", _u8L("Set left alignment").c_str());
ImGui::SameLine();
- if (is_center_h(align)) Slic3r::GUI::draw(get_icon(icons, IconType::align_horizontal_center, IconState::hovered));
- else if (draw_button(icons, IconType::align_horizontal_center)) { to_center_h(align); is_change = true; }
+ if (align.first==FontProp::HorizontalAlign::center) draw(get_icon(icons, IconType::align_horizontal_center, IconState::hovered));
+ else if (draw_button(icons, IconType::align_horizontal_center)) { align.first=FontProp::HorizontalAlign::center; is_change = true; }
+ else if (ImGui::IsItemHovered()) ImGui::SetTooltip("%s", _u8L("Set horizont center alignment").c_str());
ImGui::SameLine();
- if (is_right(align)) Slic3r::GUI::draw(get_icon(icons, IconType::align_horizontal_right, IconState::hovered));
- else if (draw_button(icons, IconType::align_horizontal_right)) { to_right(align); is_change = true; }
+ if (align.first==FontProp::HorizontalAlign::right) draw(get_icon(icons, IconType::align_horizontal_right, IconState::hovered));
+ else if (draw_button(icons, IconType::align_horizontal_right)) { align.first=FontProp::HorizontalAlign::right; is_change = true; }
+ else if (ImGui::IsItemHovered()) ImGui::SetTooltip("%s", _u8L("Set right alignment").c_str());
ImGui::SameLine();
- if (is_top(align)) Slic3r::GUI::draw(get_icon(icons, IconType::align_vertical_top, IconState::hovered));
- else if (draw_button(icons, IconType::align_vertical_top)) { to_top(align); is_change = true; }
+ if (align.second==FontProp::VerticalAlign::top) draw(get_icon(icons, IconType::align_vertical_top, IconState::hovered));
+ else if (draw_button(icons, IconType::align_vertical_top)) { align.second=FontProp::VerticalAlign::top; is_change = true; }
+ else if (ImGui::IsItemHovered()) ImGui::SetTooltip("%s", _u8L("Set top alignment").c_str());
ImGui::SameLine();
- if (is_center_v(align)) Slic3r::GUI::draw(get_icon(icons, IconType::align_vertical_center, IconState::hovered));
- else if (draw_button(icons, IconType::align_vertical_center)) { to_center_v(align); is_change = true; }
+ if (align.second==FontProp::VerticalAlign::center) draw(get_icon(icons, IconType::align_vertical_center, IconState::hovered));
+ else if (draw_button(icons, IconType::align_vertical_center)) { align.second=FontProp::VerticalAlign::center; is_change = true; }
+ else if (ImGui::IsItemHovered()) ImGui::SetTooltip("%s", _u8L("Set vertical center alignment").c_str());
ImGui::SameLine();
- if (is_bottom(align)) Slic3r::GUI::draw(get_icon(icons, IconType::align_vertical_bottom, IconState::hovered));
- else if (draw_button(icons, IconType::align_vertical_bottom)) { to_bottom(align); is_change = true; }
+ if (align.second==FontProp::VerticalAlign::bottom) draw(get_icon(icons, IconType::align_vertical_bottom, IconState::hovered));
+ else if (draw_button(icons, IconType::align_vertical_bottom)) { align.second=FontProp::VerticalAlign::bottom; is_change = true; }
+ else if (ImGui::IsItemHovered()) ImGui::SetTooltip("%s", _u8L("Set bottom alignment").c_str());
return is_change;
};
-
+ const FontProp::Align * def_align = stored_style ? &stored_style->prop.align : nullptr;
+ float undo_offset = ImGui::GetStyle().FramePadding.x;
if (revertible(tr.alignment, font_prop.align, def_align, _u8L("Revert alignment."), undo_offset, draw_align)) {
if (font_prop.per_glyph)
reinit_text_lines(m_text_lines.get_lines().size());
diff --git a/src/slic3r/GUI/Jobs/EmbossJob.cpp b/src/slic3r/GUI/Jobs/EmbossJob.cpp
index b3afec427a..3b631b86ca 100644
--- a/src/slic3r/GUI/Jobs/EmbossJob.cpp
+++ b/src/slic3r/GUI/Jobs/EmbossJob.cpp
@@ -247,10 +247,6 @@ void UpdateJob::process(Ctl &ctl)
if (was_canceled()) return;
if (m_result.its.empty())
throw priv::JobException("Created text volume is empty. Change text or font.");
-
- // center triangle mesh
- //Vec3d shift = m_result.bounding_box().center();
- //m_result.translate(-shift.cast());
}
void UpdateJob::finalize(bool canceled, std::exception_ptr &eptr)