mirror of
https://git.mirrors.martin98.com/https://github.com/prusa3d/PrusaSlicer.git
synced 2025-08-13 09:29:03 +08:00
Separate horizontal and vertical align
Vertically align on base line of text to be able set base line of per glyph independent on align
This commit is contained in:
parent
6751bba96e
commit
733b70b26f
@ -1287,12 +1287,14 @@ ExPolygons Emboss::text2shapes(FontFileWithCache &font_with_cache, const char *t
|
||||
|
||||
namespace {
|
||||
/// <summary>
|
||||
/// Align expolygons by type
|
||||
/// Align shape against pivot
|
||||
/// </summary>
|
||||
/// <param name="type">Type of alignment</param>
|
||||
/// <param name="shape">shapes to align</param>
|
||||
/// <param name="text">Same size as shape for align per line(detect of end line - '\n')</param>
|
||||
void align_shape(FontProp::Align type, std::vector<ExPolygons> &shape, const std::wstring &text);
|
||||
/// <param name="type">Horizontal and vertical alignment</param>
|
||||
/// <param name="shapes">Shapes to align
|
||||
/// Prerequisities: shapes are aligned left top</param>
|
||||
/// <param name="text">To detect end of lines</param>
|
||||
/// <param name="line_height">Height of line for align[in font points]</param>
|
||||
void align_shape(FontProp::Align type, std::vector<ExPolygons> &shape, const std::wstring &text, int line_height);
|
||||
}
|
||||
|
||||
std::vector<ExPolygons> Emboss::text2vshapes(FontFileWithCache &font_with_cache, const std::wstring& text, const FontProp &font_prop, const std::function<bool()>& was_canceled){
|
||||
@ -1317,7 +1319,7 @@ std::vector<ExPolygons> 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<ExPolygons> &shapes, const std::wstring &text)
|
||||
void align_shape(FontProp::Align type, std::vector<ExPolygons> &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<ExPolygons> &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];
|
||||
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];
|
||||
|
@ -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<int>(fp.align) << "\" ";
|
||||
stream << HORIZONTAL_ALIGN_ATTR << "=\"" << static_cast<int>(fp.align.first) << "\" ";
|
||||
stream << VERTICAL_ALIGN_ATTR << "=\"" << static_cast<int>(fp.align.second) << "\" ";
|
||||
if (fp.collection_number.has_value())
|
||||
stream << COLLECTION_NUMBER_ATTR << "=\"" << *fp.collection_number << "\" ";
|
||||
// font descriptor
|
||||
@ -3617,8 +3618,12 @@ std::optional<TextConfiguration> 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<FontProp::Align>(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<FontProp::HorizontalAlign>(horizontal),
|
||||
static_cast<FontProp::VerticalAlign>(vertical));
|
||||
|
||||
int collection_number = get_attribute_value_int(attributes, num_attributes, COLLECTION_NUMBER_ATTR);
|
||||
if (collection_number > 0) fp.collection_number = static_cast<unsigned int>(collection_number);
|
||||
|
@ -63,26 +63,13 @@ 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<HorizontalAlign, VerticalAlign>;
|
||||
// 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
|
||||
@ -126,7 +113,7 @@ struct FontProp
|
||||
// undo / redo stack recovery
|
||||
template<class Archive> 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<class Archive> 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);
|
||||
|
@ -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());
|
||||
|
@ -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<float>());
|
||||
}
|
||||
|
||||
void UpdateJob::finalize(bool canceled, std::exception_ptr &eptr)
|
||||
|
Loading…
x
Reference in New Issue
Block a user